BrowserChild.cpp (156483B)
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 #include "BrowserChild.h" 8 9 #ifdef ACCESSIBILITY 10 # include "mozilla/a11y/DocAccessibleChild.h" 11 #endif 12 #include <utility> 13 14 #include "BrowserParent.h" 15 #include "ContentChild.h" 16 #include "EventStateManager.h" 17 #include "MMPrinter.h" 18 #include "PuppetWidget.h" 19 #include "StructuredCloneData.h" 20 #include "UnitTransforms.h" 21 #include "Units.h" 22 #include "VRManagerChild.h" 23 #include "mozilla/Assertions.h" 24 #include "mozilla/BasePrincipal.h" 25 #include "mozilla/EventForwards.h" 26 #include "mozilla/EventListenerManager.h" 27 #include "mozilla/HoldDropJSObjects.h" 28 #include "mozilla/IMEStateManager.h" 29 #include "mozilla/LookAndFeel.h" 30 #include "mozilla/MediaFeatureChange.h" 31 #include "mozilla/MiscEvents.h" 32 #include "mozilla/MouseEvents.h" 33 #include "mozilla/NativeKeyBindingsType.h" 34 #include "mozilla/NullPrincipal.h" 35 #include "mozilla/PointerLockManager.h" 36 #include "mozilla/PresShell.h" 37 #include "mozilla/ProcessHangMonitor.h" 38 #include "mozilla/ProfilerLabels.h" 39 #include "mozilla/SchedulerGroup.h" 40 #include "mozilla/ScopeExit.h" 41 #include "mozilla/Services.h" 42 #include "mozilla/StaticPrefs_dom.h" 43 #include "mozilla/TextEvents.h" 44 #include "mozilla/ToString.h" 45 #include "mozilla/dom/AutoPrintEventDispatcher.h" 46 #include "mozilla/dom/BrowserBridgeChild.h" 47 #include "mozilla/dom/DataTransfer.h" 48 #include "mozilla/dom/Element.h" 49 #include "mozilla/dom/Event.h" 50 #include "mozilla/dom/ImageDocument.h" 51 #include "mozilla/dom/JSWindowActorChild.h" 52 #include "mozilla/dom/LoadURIOptionsBinding.h" 53 #include "mozilla/dom/MessageManagerBinding.h" 54 #include "mozilla/dom/MouseEventBinding.h" 55 #include "mozilla/dom/Nullable.h" 56 #include "mozilla/dom/PBrowser.h" 57 #include "mozilla/dom/PaymentRequestChild.h" 58 #include "mozilla/dom/PointerEventHandler.h" 59 #include "mozilla/dom/SessionStoreChild.h" 60 #include "mozilla/dom/SessionStoreUtils.h" 61 #include "mozilla/dom/UserActivation.h" 62 #include "mozilla/dom/ViewTransition.h" 63 #include "mozilla/dom/WindowGlobalChild.h" 64 #include "mozilla/dom/WindowProxyHolder.h" 65 #include "mozilla/gfx/CrossProcessPaint.h" 66 #include "mozilla/gfx/Matrix.h" 67 #include "mozilla/ipc/BackgroundChild.h" 68 #include "mozilla/ipc/BackgroundUtils.h" 69 #include "mozilla/ipc/PBackgroundChild.h" 70 #include "mozilla/layers/APZCCallbackHelper.h" 71 #include "mozilla/layers/APZCTreeManagerChild.h" 72 #include "mozilla/layers/APZChild.h" 73 #include "mozilla/layers/APZEventState.h" 74 #include "mozilla/layers/CompositorBridgeChild.h" 75 #include "mozilla/layers/ContentProcessController.h" 76 #include "mozilla/layers/DoubleTapToZoom.h" 77 #include "mozilla/layers/IAPZCTreeManager.h" 78 #include "mozilla/layers/ImageBridgeChild.h" 79 #include "mozilla/layers/InputAPZContext.h" 80 #include "mozilla/layers/TouchActionHelper.h" 81 #include "mozilla/layers/WebRenderLayerManager.h" 82 #include "mozilla/widget/ScreenManager.h" 83 #include "mozilla/widget/WidgetLogging.h" 84 #include "nsCommandParams.h" 85 #include "nsContentPermissionHelper.h" 86 #include "nsContentUtils.h" 87 #include "nsDeviceContext.h" 88 #include "nsDocShell.h" 89 #include "nsDocShellLoadState.h" 90 #include "nsDragServiceProxy.h" 91 #include "nsExceptionHandler.h" 92 #include "nsFilePickerProxy.h" 93 #include "nsFocusManager.h" 94 #include "nsGlobalWindowOuter.h" 95 #include "nsIBaseWindow.h" 96 #include "nsIBrowserDOMWindow.h" 97 #include "nsIClassifiedChannel.h" 98 #include "nsIDocShell.h" 99 #include "nsIFrame.h" 100 #include "nsILoadContext.h" 101 #include "nsIOpenWindowInfo.h" 102 #include "nsISHEntry.h" 103 #include "nsISHistory.h" 104 #include "nsIScreenManager.h" 105 #include "nsIScriptError.h" 106 #include "nsIURI.h" 107 #include "nsIURIMutator.h" 108 #include "nsIWeakReferenceUtils.h" 109 #include "nsIWebBrowser.h" 110 #include "nsIWebProgress.h" 111 #include "nsIXULRuntime.h" 112 #include "nsLayoutUtils.h" 113 #include "nsNetUtil.h" 114 #include "nsPIDOMWindow.h" 115 #include "nsPIWindowRoot.h" 116 #include "nsPrintfCString.h" 117 #include "nsRefreshDriver.h" 118 #include "nsThreadManager.h" 119 #include "nsThreadUtils.h" 120 #include "nsVariant.h" 121 #include "nsWebBrowser.h" 122 #include "nsWindowWatcher.h" 123 124 #ifdef MOZ_WAYLAND 125 # include "nsAppRunner.h" 126 #endif 127 128 #ifdef NS_PRINTING 129 # include "mozilla/layout/RemotePrintJobChild.h" 130 # include "nsIPrintSettings.h" 131 # include "nsIPrintSettingsService.h" 132 # include "nsIWebBrowserPrint.h" 133 #endif 134 135 static mozilla::LazyLogModule sApzChildLog("apz.child"); 136 137 using namespace mozilla; 138 using namespace mozilla::dom; 139 using namespace mozilla::dom::ipc; 140 using namespace mozilla::ipc; 141 using namespace mozilla::layers; 142 using namespace mozilla::layout; 143 using namespace mozilla::widget; 144 using mozilla::layers::GeckoContentController; 145 146 static const char BEFORE_FIRST_PAINT[] = "before-first-paint"; 147 148 static uint32_t sConsecutiveTouchMoveCount = 0; 149 150 using BrowserChildMap = nsTHashMap<nsUint64HashKey, BrowserChild*>; 151 static BrowserChildMap* sBrowserChildren; 152 StaticMutex sBrowserChildrenMutex; 153 154 namespace { 155 156 class SynthesizedEventChildCallback final : public nsISynthesizedEventCallback { 157 NS_DECL_ISUPPORTS 158 159 public: 160 SynthesizedEventChildCallback(BrowserChild* aBrowserChild, 161 const uint64_t& aCallbackId) 162 : mBrowserChild(aBrowserChild), mCallbackId(aCallbackId) { 163 MOZ_ASSERT(mBrowserChild); 164 MOZ_ASSERT(mCallbackId > 0, "Invalid callback ID"); 165 } 166 167 NS_IMETHOD OnCompleteDispatch() override { 168 MOZ_ASSERT(mCallbackId > 0, "Invalid callback ID"); 169 170 if (!mBrowserChild) { 171 // We already sent the notification, or we don't actually need to 172 // send any notification at all. 173 MOZ_ASSERT_UNREACHABLE("OnCompleteDispatch called multiple times"); 174 return NS_OK; 175 } 176 177 if (mBrowserChild->IsDestroyed()) { 178 // If this happens it's probably a bug in the test that's triggering this. 179 NS_WARNING( 180 "BrowserChild was unexpectedly destroyed during event " 181 "synthesization response!"); 182 } else if (!mBrowserChild->SendSynthesizedEventResponse(mCallbackId)) { 183 NS_WARNING("Unable to send event synthesization response!"); 184 } 185 // Null out browserChild to indicate we already sent the response 186 mBrowserChild = nullptr; 187 return NS_OK; 188 } 189 190 private: 191 virtual ~SynthesizedEventChildCallback() = default; 192 193 RefPtr<BrowserChild> mBrowserChild; 194 uint64_t mCallbackId; 195 }; 196 197 NS_IMPL_ISUPPORTS(SynthesizedEventChildCallback, nsISynthesizedEventCallback) 198 199 template <class T> 200 class MOZ_RAII AutoSynthesizedEventResponder final { 201 public: 202 AutoSynthesizedEventResponder(BrowserChild* aBrowserChild, const T& aEvent) { 203 if (aEvent.mCallbackId.isSome()) { 204 mCallback = MakeAndAddRef<SynthesizedEventChildCallback>( 205 aBrowserChild, aEvent.mCallbackId.ref()); 206 } 207 } 208 209 ~AutoSynthesizedEventResponder() { 210 if (mCallback) { 211 mCallback->OnCompleteDispatch(); 212 } 213 } 214 215 private: 216 nsCOMPtr<nsISynthesizedEventCallback> mCallback; 217 }; 218 219 } // namespace 220 221 already_AddRefed<Document> BrowserChild::GetTopLevelDocument() const { 222 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); 223 nsCOMPtr<Document> doc = docShell ? docShell->GetExtantDocument() : nullptr; 224 return doc.forget(); 225 } 226 227 PresShell* BrowserChild::GetTopLevelPresShell() const { 228 if (RefPtr<Document> doc = GetTopLevelDocument()) { 229 return doc->GetPresShell(); 230 } 231 return nullptr; 232 } 233 234 bool BrowserChild::UpdateFrame(const RepaintRequest& aRequest) { 235 MOZ_ASSERT(aRequest.GetScrollId() != ScrollableLayerGuid::NULL_SCROLL_ID); 236 237 if (aRequest.IsRootContent()) { 238 if (PresShell* presShell = GetTopLevelPresShell()) { 239 // Guard against stale updates (updates meant for a pres shell which 240 // has since been torn down and destroyed). 241 if (aRequest.GetPresShellId() == presShell->GetPresShellId()) { 242 APZCCallbackHelper::UpdateRootFrame(aRequest); 243 return true; 244 } 245 } 246 } else { 247 // aRequest.mIsRoot is false, so we are trying to update a subframe. 248 // This requires special handling. 249 APZCCallbackHelper::UpdateSubFrame(aRequest); 250 return true; 251 } 252 return true; 253 } 254 255 class BrowserChild::DelayedDeleteRunnable final : public Runnable, 256 public nsIRunnablePriority { 257 RefPtr<BrowserChild> mBrowserChild; 258 259 // In order to try that this runnable runs after everything that could 260 // possibly touch this tab, we send it through the event queue twice. 261 bool mReadyToDelete = false; 262 263 public: 264 explicit DelayedDeleteRunnable(BrowserChild* aBrowserChild) 265 : Runnable("BrowserChild::DelayedDeleteRunnable"), 266 mBrowserChild(aBrowserChild) { 267 MOZ_ASSERT(NS_IsMainThread()); 268 MOZ_ASSERT(aBrowserChild); 269 } 270 271 NS_DECL_ISUPPORTS_INHERITED 272 273 private: 274 ~DelayedDeleteRunnable() { 275 MOZ_ASSERT(NS_IsMainThread()); 276 MOZ_ASSERT(!mBrowserChild); 277 } 278 279 NS_IMETHOD GetPriority(uint32_t* aPriority) override { 280 *aPriority = nsIRunnablePriority::PRIORITY_NORMAL; 281 return NS_OK; 282 } 283 284 NS_IMETHOD 285 Run() override { 286 MOZ_ASSERT(NS_IsMainThread()); 287 MOZ_ASSERT(mBrowserChild); 288 289 if (!mReadyToDelete) { 290 // This time run this runnable at input priority. 291 mReadyToDelete = true; 292 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this)); 293 return NS_OK; 294 } 295 296 // Check in case ActorDestroy was called after RecvDestroy message. 297 if (mBrowserChild->IPCOpen()) { 298 (void)PBrowserChild::Send__delete__(mBrowserChild); 299 } 300 301 mBrowserChild = nullptr; 302 return NS_OK; 303 } 304 }; 305 306 NS_IMPL_ISUPPORTS_INHERITED(BrowserChild::DelayedDeleteRunnable, Runnable, 307 nsIRunnablePriority) 308 309 namespace { 310 std::map<TabId, RefPtr<BrowserChild>>& NestedBrowserChildMap() { 311 MOZ_ASSERT(NS_IsMainThread()); 312 static std::map<TabId, RefPtr<BrowserChild>> sNestedBrowserChildMap; 313 return sNestedBrowserChildMap; 314 } 315 } // namespace 316 317 already_AddRefed<BrowserChild> BrowserChild::FindBrowserChild( 318 const TabId& aTabId) { 319 auto iter = NestedBrowserChildMap().find(aTabId); 320 if (iter == NestedBrowserChildMap().end()) { 321 return nullptr; 322 } 323 RefPtr<BrowserChild> browserChild = iter->second; 324 return browserChild.forget(); 325 } 326 327 /*static*/ 328 already_AddRefed<BrowserChild> BrowserChild::Create( 329 ContentChild* aManager, const TabId& aTabId, const TabContext& aContext, 330 BrowsingContext* aBrowsingContext, uint32_t aChromeFlags, 331 bool aIsTopLevel) { 332 RefPtr<BrowserChild> iframe = new BrowserChild( 333 aManager, aTabId, aContext, aBrowsingContext, aChromeFlags, aIsTopLevel); 334 return iframe.forget(); 335 } 336 337 BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId, 338 const TabContext& aContext, 339 BrowsingContext* aBrowsingContext, 340 uint32_t aChromeFlags, bool aIsTopLevel) 341 : TabContext(aContext), 342 mBrowserChildMessageManager(nullptr), 343 mManager(aManager), 344 mBrowsingContext(aBrowsingContext), 345 mChromeFlags(aChromeFlags), 346 mMaxTouchPoints(0), 347 mLayersId{0}, 348 mEffectsInfo{EffectsInfo::FullyHidden()}, 349 mDynamicToolbarMaxHeight(0), 350 mKeyboardHeight(0), 351 mUniqueId(aTabId), 352 mDidFakeShow(false), 353 mTriedBrowserInit(false), 354 mHasValidInnerSize(false), 355 mDestroyed(false), 356 mInAndroidPipMode(false), 357 mIsTopLevel(aIsTopLevel), 358 mIsTransparent(false), 359 mIPCOpen(false), 360 mDidSetRealShowInfo(false), 361 mDidLoadURLInit(false), 362 mSkipKeyPress(false), 363 mShouldSendWebProgressEventsToParent(false), 364 mRenderLayers(true), 365 mIsPreservingLayers(false), 366 #if defined(XP_WIN) && defined(ACCESSIBILITY) 367 mNativeWindowHandle(0), 368 #endif 369 mCancelContentJSEpoch(0) { 370 mozilla::HoldJSObjects(this); 371 372 // preloaded BrowserChild should not be added to child map 373 if (mUniqueId) { 374 MOZ_ASSERT(NestedBrowserChildMap().find(mUniqueId) == 375 NestedBrowserChildMap().end()); 376 NestedBrowserChildMap()[mUniqueId] = this; 377 } 378 mCoalesceMouseMoveEvents = StaticPrefs::dom_events_coalesce_mousemove(); 379 if (mCoalesceMouseMoveEvents) { 380 mCoalescedMouseEventFlusher = new CoalescedMouseMoveFlusher(this); 381 } 382 383 if (StaticPrefs::dom_events_coalesce_touchmove()) { 384 mCoalescedTouchMoveEventFlusher = new CoalescedTouchMoveFlusher(this); 385 } 386 } 387 388 const CompositorOptions& BrowserChild::GetCompositorOptions() const { 389 // If you're calling this before mCompositorOptions is set, well.. don't. 390 MOZ_ASSERT(mCompositorOptions); 391 return mCompositorOptions.ref(); 392 } 393 394 bool BrowserChild::AsyncPanZoomEnabled() const { 395 // This might get called by the TouchEvent::PrefEnabled code before we have 396 // mCompositorOptions populated (bug 1370089). In that case we just assume 397 // APZ is enabled because we're in a content process (because BrowserChild) 398 // and APZ is probably going to be enabled here since e10s is enabled. 399 return mCompositorOptions ? mCompositorOptions->UseAPZ() : true; 400 } 401 402 NS_IMETHODIMP 403 BrowserChild::Observe(nsISupports* aSubject, const char* aTopic, 404 const char16_t* aData) { 405 if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) { 406 if (AsyncPanZoomEnabled()) { 407 nsCOMPtr<Document> subject(do_QueryInterface(aSubject)); 408 nsCOMPtr<Document> doc(GetTopLevelDocument()); 409 410 if (subject == doc) { 411 RefPtr<PresShell> presShell = doc->GetPresShell(); 412 if (presShell) { 413 presShell->SetIsFirstPaint(true); 414 } 415 416 APZCCallbackHelper::InitializeRootDisplayport(presShell); 417 } 418 } 419 } 420 421 return NS_OK; 422 } 423 424 void BrowserChild::ContentReceivedInputBlock(uint64_t aInputBlockId, 425 bool aPreventDefault) const { 426 if (mApzcTreeManager) { 427 mApzcTreeManager->ContentReceivedInputBlock(aInputBlockId, aPreventDefault); 428 } 429 } 430 431 void BrowserChild::SetTargetAPZC( 432 uint64_t aInputBlockId, 433 const nsTArray<ScrollableLayerGuid>& aTargets) const { 434 if (mApzcTreeManager) { 435 mApzcTreeManager->SetTargetAPZC(aInputBlockId, aTargets); 436 } 437 } 438 439 bool BrowserChild::DoUpdateZoomConstraints( 440 const uint32_t& aPresShellId, const ViewID& aViewId, 441 const Maybe<ZoomConstraints>& aConstraints) { 442 if (!mApzcTreeManager || mDestroyed) { 443 return false; 444 } 445 446 ScrollableLayerGuid guid = 447 ScrollableLayerGuid(mLayersId, aPresShellId, aViewId); 448 449 mApzcTreeManager->UpdateZoomConstraints(guid, aConstraints); 450 return true; 451 } 452 453 nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent, 454 WindowGlobalChild* aInitialWindowChild, 455 nsIOpenWindowInfo* aOpenWindowInfo) { 456 MOZ_ASSERT(aOpenWindowInfo, "Must have openwindowinfo"); 457 MOZ_ASSERT(aInitialWindowChild, "Must have window child"); 458 MOZ_ASSERT(aInitialWindowChild->BrowsingContext() == mBrowsingContext); 459 MOZ_ASSERT(aInitialWindowChild->DocumentPrincipal() == 460 aOpenWindowInfo->PrincipalToInheritForAboutBlank()); 461 462 nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(this); 463 mPuppetWidget = static_cast<PuppetWidget*>(widget.get()); 464 if (!mPuppetWidget) { 465 NS_ERROR("couldn't create fake widget"); 466 return NS_ERROR_FAILURE; 467 } 468 mPuppetWidget->InfallibleCreate(nullptr, LayoutDeviceIntRect(), 469 widget::InitData()); 470 471 mWebBrowser = nsWebBrowser::Create(this, mPuppetWidget, mBrowsingContext, 472 aInitialWindowChild, aOpenWindowInfo); 473 if (!mWebBrowser) { 474 // At least the JS recursion depth check can cause an early return 475 // here. dom/base/crashtests/1419902.html 476 return NS_ERROR_FAILURE; 477 } 478 nsIWebBrowser* webBrowser = mWebBrowser; 479 480 mWebNav = do_QueryInterface(webBrowser); 481 NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?"); 482 483 // IPC uses a WebBrowser object for which DNS prefetching is turned off 484 // by default. But here we really want it, so enable it explicitly 485 mWebBrowser->SetAllowDNSPrefetch(true); 486 487 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); 488 MOZ_ASSERT(docShell); 489 490 #ifdef DEBUG 491 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation()); 492 MOZ_ASSERT(loadContext); 493 MOZ_ASSERT(loadContext->UseRemoteTabs() == 494 !!(mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW)); 495 MOZ_ASSERT(loadContext->UseRemoteSubframes() == 496 !!(mChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW)); 497 #endif // defined(DEBUG) 498 499 // Few lines before, baseWindow->Create() will end up creating a new 500 // window root in nsGlobalWindowOuter::SetDocShell. 501 // Then this chrome event handler, will be inherited to inner windows. 502 // We want to also set it to the docshell so that inner windows 503 // and any code that has access to the docshell 504 // can all listen to the same chrome event handler. 505 // XXX: ideally, we would set a chrome event handler earlier, 506 // and all windows, even the root one, will use the docshell one. 507 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); 508 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 509 nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler(); 510 docShell->SetChromeEventHandler(chromeHandler); 511 512 // Window scrollbar flags only affect top level remote frames, not fission 513 // frames. 514 if (mIsTopLevel) { 515 nsContentUtils::SetScrollbarsVisibility( 516 docShell, !!(mChromeFlags & nsIWebBrowserChrome::CHROME_SCROLLBARS)); 517 } 518 519 nsWeakPtr weakPtrThis = do_GetWeakReference( 520 static_cast<nsIBrowserChild*>(this)); // for capture by the lambda 521 ContentReceivedInputBlockCallback callback( 522 [weakPtrThis](uint64_t aInputBlockId, bool aPreventDefault) { 523 if (nsCOMPtr<nsIBrowserChild> browserChild = 524 do_QueryReferent(weakPtrThis)) { 525 static_cast<BrowserChild*>(browserChild.get()) 526 ->ContentReceivedInputBlock(aInputBlockId, aPreventDefault); 527 } 528 }); 529 mAPZEventState = new APZEventState(mPuppetWidget, std::move(callback)); 530 531 mIPCOpen = true; 532 533 if (SessionStorePlatformCollection()) { 534 mSessionStoreChild = SessionStoreChild::GetOrCreate(mBrowsingContext); 535 } 536 537 // We've all set up, make sure our visibility state is consistent. This is 538 // important for OOP iframes, which start off as hidden. 539 UpdateVisibility(); 540 541 return NS_OK; 542 } 543 544 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowserChild) 545 546 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowserChild) 547 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChildMessageManager) 548 tmp->nsMessageManagerScriptExecutor::Unlink(); 549 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebBrowser) 550 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebNav) 551 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext) 552 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreChild) 553 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContentTransformPromise) 554 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE 555 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 556 557 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowserChild) 558 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChildMessageManager) 559 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebBrowser) 560 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebNav) 561 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext) 562 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreChild) 563 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentTransformPromise) 564 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 565 566 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowserChild) 567 tmp->nsMessageManagerScriptExecutor::Trace(aCallbacks, aClosure); 568 NS_IMPL_CYCLE_COLLECTION_TRACE_END 569 570 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChild) 571 NS_INTERFACE_MAP_ENTRY_CONCRETE(BrowserChild) 572 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome) 573 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) 574 NS_INTERFACE_MAP_ENTRY(nsIWindowProvider) 575 NS_INTERFACE_MAP_ENTRY(nsIBrowserChild) 576 NS_INTERFACE_MAP_ENTRY(nsIObserver) 577 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 578 NS_INTERFACE_MAP_ENTRY(nsITooltipListener) 579 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) 580 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIBrowserChild) 581 NS_INTERFACE_MAP_END 582 583 NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowserChild) 584 NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowserChild) 585 586 NS_IMETHODIMP 587 BrowserChild::GetChromeFlags(uint32_t* aChromeFlags) { 588 *aChromeFlags = mChromeFlags; 589 return NS_OK; 590 } 591 592 NS_IMETHODIMP 593 BrowserChild::SetChromeFlags(uint32_t aChromeFlags) { 594 NS_WARNING("trying to SetChromeFlags from content process?"); 595 596 return NS_ERROR_NOT_IMPLEMENTED; 597 } 598 599 NS_IMETHODIMP 600 BrowserChild::RemoteDropLinks( 601 const nsTArray<RefPtr<nsIDroppedLinkItem>>& aLinks) { 602 nsTArray<nsString> linksArray; 603 nsresult rv = NS_OK; 604 for (nsIDroppedLinkItem* link : aLinks) { 605 nsString tmp; 606 rv = link->GetUrl(tmp); 607 if (NS_FAILED(rv)) { 608 return rv; 609 } 610 linksArray.AppendElement(tmp); 611 612 rv = link->GetName(tmp); 613 if (NS_FAILED(rv)) { 614 return rv; 615 } 616 linksArray.AppendElement(tmp); 617 618 rv = link->GetType(tmp); 619 if (NS_FAILED(rv)) { 620 return rv; 621 } 622 linksArray.AppendElement(tmp); 623 } 624 bool sent = SendDropLinks(linksArray); 625 626 return sent ? NS_OK : NS_ERROR_FAILURE; 627 } 628 629 NS_IMETHODIMP 630 BrowserChild::ShowAsModal() { 631 NS_WARNING("BrowserChild::ShowAsModal not supported in BrowserChild"); 632 633 return NS_ERROR_NOT_IMPLEMENTED; 634 } 635 636 NS_IMETHODIMP 637 BrowserChild::IsWindowModal(bool* aRetVal) { 638 *aRetVal = false; 639 return NS_OK; 640 } 641 642 NS_IMETHODIMP 643 BrowserChild::SetLinkStatus(const nsAString& aStatusText) { 644 // We can only send the status after the ipc machinery is set up 645 if (IPCOpen()) { 646 SendSetLinkStatus(aStatusText); 647 } 648 return NS_OK; 649 } 650 651 NS_IMETHODIMP 652 BrowserChild::SetDimensions(DimensionRequest&& aRequest) { 653 // The parent is in charge of the dimension changes. If JS code wants to 654 // change the dimensions (moveTo, screenX, etc.) we send a message to the 655 // parent about the new requested dimension, the parent does the resize/move 656 // then send a message to the child to update itself. For APIs like screenX 657 // this function is called with only the changed values. In a series of calls 658 // like window.screenX = 10; window.screenY = 10; for the second call, since 659 // screenX is not yet updated we might accidentally reset back screenX to it's 660 // old value. To avoid this, if a parameter did not change, we want the parent 661 // to handle the unchanged values. 662 663 double scale = mPuppetWidget ? mPuppetWidget->GetDefaultScale().scale : 1.0; 664 SendSetDimensions(aRequest, scale); 665 return NS_OK; 666 } 667 668 NS_IMETHODIMP 669 BrowserChild::GetDimensions(DimensionKind aDimensionKind, int32_t* aX, 670 int32_t* aY, int32_t* aCx, int32_t* aCy) { 671 LayoutDeviceIntRect rect = GetOuterRect(); 672 if (aDimensionKind == DimensionKind::Inner) { 673 if (aX || aY) { 674 return NS_ERROR_NOT_IMPLEMENTED; 675 } 676 rect.SizeTo(GetInnerSize()); 677 } 678 if (aX) { 679 *aX = rect.x; 680 } 681 if (aY) { 682 *aY = rect.y; 683 } 684 if (aCx) { 685 *aCx = rect.width; 686 } 687 if (aCy) { 688 *aCy = rect.height; 689 } 690 return NS_OK; 691 } 692 693 NS_IMETHODIMP 694 BrowserChild::Blur() { return NS_ERROR_NOT_IMPLEMENTED; } 695 696 NS_IMETHODIMP 697 BrowserChild::GetInterface(const nsIID& aIID, void** aSink) { 698 // XXXbz should we restrict the set of interfaces we hand out here? 699 // See bug 537429 700 return QueryInterface(aIID, aSink); 701 } 702 703 NS_IMETHODIMP 704 BrowserChild::ProvideWindow(nsIOpenWindowInfo* aOpenWindowInfo, 705 uint32_t aChromeFlags, bool aCalledFromJS, 706 nsIURI* aURI, const nsAString& aName, 707 const nsACString& aFeatures, 708 const UserActivation::Modifiers& aModifiers, 709 bool aForceNoOpener, bool aForceNoReferrer, 710 bool aIsPopupRequested, 711 nsDocShellLoadState* aLoadState, bool* aWindowIsNew, 712 BrowsingContext** aReturn) { 713 *aReturn = nullptr; 714 715 RefPtr<BrowsingContext> parent = aOpenWindowInfo->GetParent(); 716 717 int32_t openLocation = nsWindowWatcher::GetWindowOpenLocation( 718 parent->GetDOMWindow(), aChromeFlags, aModifiers, aCalledFromJS, 719 aOpenWindowInfo->GetIsForPrinting()); 720 721 // If it turns out we're opening in the current browser, just hand over the 722 // current browser's docshell. 723 if (openLocation == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) { 724 nsCOMPtr<nsIWebBrowser> browser = do_GetInterface(WebNavigation()); 725 *aWindowIsNew = false; 726 727 nsCOMPtr<mozIDOMWindowProxy> win; 728 MOZ_TRY(browser->GetContentDOMWindow(getter_AddRefs(win))); 729 730 RefPtr<BrowsingContext> bc( 731 nsPIDOMWindowOuter::From(win)->GetBrowsingContext()); 732 bc.forget(aReturn); 733 return NS_OK; 734 } 735 736 // Note that ProvideWindowCommon may return NS_ERROR_ABORT if the 737 // open window call was canceled. It's important that we pass this error 738 // code back to our caller. 739 ContentChild* cc = ContentChild::GetSingleton(); 740 return cc->ProvideWindowCommon( 741 WrapNotNull(this), aOpenWindowInfo, aChromeFlags, aCalledFromJS, aURI, 742 aName, aFeatures, aModifiers, aForceNoOpener, aForceNoReferrer, 743 aIsPopupRequested, aLoadState, aWindowIsNew, aReturn); 744 } 745 746 void BrowserChild::DestroyWindow() { 747 mBrowsingContext = nullptr; 748 749 if (mCoalescedMouseEventFlusher) { 750 mCoalescedMouseEventFlusher->RemoveObserver(); 751 mCoalescedMouseEventFlusher = nullptr; 752 } 753 754 if (mCoalescedTouchMoveEventFlusher) { 755 mCoalescedTouchMoveEventFlusher->RemoveObserver(); 756 mCoalescedTouchMoveEventFlusher = nullptr; 757 } 758 759 if (mSessionStoreChild) { 760 mSessionStoreChild->Stop(); 761 mSessionStoreChild = nullptr; 762 } 763 764 // In case we don't have chance to process all entries, clean all data in 765 // the queue. 766 while (mToBeDispatchedMouseData.GetSize() > 0) { 767 UniquePtr<CoalescedMouseData> data( 768 static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront())); 769 data.reset(); 770 } 771 772 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation()); 773 if (baseWindow) baseWindow->Destroy(); 774 775 if (mPuppetWidget) { 776 mPuppetWidget->Destroy(); 777 } 778 779 mLayersConnected = Nothing(); 780 781 if (mLayersId.IsValid()) { 782 StaticMutexAutoLock lock(sBrowserChildrenMutex); 783 784 MOZ_ASSERT(sBrowserChildren); 785 sBrowserChildren->Remove(uint64_t(mLayersId)); 786 if (!sBrowserChildren->Count()) { 787 delete sBrowserChildren; 788 sBrowserChildren = nullptr; 789 } 790 mLayersId = layers::LayersId{0}; 791 } 792 793 if (mAPZEventState) { 794 mAPZEventState->Destroy(); 795 mAPZEventState = nullptr; 796 } 797 } 798 799 void BrowserChild::ActorDestroy(ActorDestroyReason why) { 800 mIPCOpen = false; 801 802 DestroyWindow(); 803 804 if (mBrowserChildMessageManager) { 805 // We should have a message manager if the global is alive, but it 806 // seems sometimes we don't. Assert in aurora/nightly, but don't 807 // crash in release builds. 808 MOZ_DIAGNOSTIC_ASSERT(mBrowserChildMessageManager->GetMessageManager()); 809 if (mBrowserChildMessageManager->GetMessageManager()) { 810 // The messageManager relays messages via the BrowserChild which 811 // no longer exists. 812 mBrowserChildMessageManager->DisconnectMessageManager(); 813 } 814 } 815 816 if (GetTabId() != 0) { 817 NestedBrowserChildMap().erase(GetTabId()); 818 } 819 } 820 821 BrowserChild::~BrowserChild() { 822 mAnonymousGlobalScopes.Clear(); 823 824 DestroyWindow(); 825 826 nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation()); 827 if (webBrowser) { 828 webBrowser->SetContainerWindow(nullptr); 829 } 830 831 mozilla::DropJSObjects(this); 832 } 833 834 mozilla::ipc::IPCResult BrowserChild::RecvWillChangeProcess() { 835 if (mWebBrowser) { 836 mWebBrowser->SetWillChangeProcess(); 837 } 838 return IPC_OK(); 839 } 840 841 mozilla::ipc::IPCResult BrowserChild::RecvLoadURL( 842 nsDocShellLoadState* aLoadState, const ParentShowInfo& aInfo) { 843 if (!mDidLoadURLInit) { 844 mDidLoadURLInit = true; 845 if (!InitBrowserChildMessageManager()) { 846 return IPC_FAIL_NO_REASON(this); 847 } 848 849 ApplyParentShowInfo(aInfo); 850 } 851 nsAutoCString spec; 852 aLoadState->URI()->GetSpec(spec); 853 854 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); 855 if (!docShell) { 856 NS_WARNING("WebNavigation does not have a docshell"); 857 return IPC_OK(); 858 } 859 docShell->LoadURI(aLoadState, true); 860 861 CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL, 862 spec); 863 return IPC_OK(); 864 } 865 866 mozilla::ipc::IPCResult BrowserChild::RecvCreateAboutBlankDocumentViewer( 867 nsIPrincipal* aPrincipal, nsIPrincipal* aPartitionedPrincipal) { 868 if (aPrincipal->GetIsExpandedPrincipal() || 869 aPartitionedPrincipal->GetIsExpandedPrincipal()) { 870 return IPC_FAIL(this, "Cannot create document with an expanded principal"); 871 } 872 if (aPrincipal->IsSystemPrincipal() || 873 aPartitionedPrincipal->IsSystemPrincipal()) { 874 MOZ_ASSERT_UNREACHABLE( 875 "Cannot use CreateAboutBlankDocumentViewer to create system principal " 876 "document in content"); 877 return IPC_OK(); 878 } 879 880 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); 881 if (!docShell) { 882 MOZ_ASSERT_UNREACHABLE("WebNavigation does not have a docshell"); 883 return IPC_OK(); 884 } 885 886 nsCOMPtr<nsIURI> currentURI; 887 MOZ_ALWAYS_SUCCEEDS( 888 WebNavigation()->GetCurrentURI(getter_AddRefs(currentURI))); 889 if (!currentURI || !NS_IsAboutBlank(currentURI)) { 890 NS_WARNING("Can't create a DocumentViewer unless on about:blank"); 891 return IPC_OK(); 892 } 893 894 docShell->CreateAboutBlankDocumentViewer(aPrincipal, aPartitionedPrincipal, 895 nullptr); 896 return IPC_OK(); 897 } 898 899 mozilla::ipc::IPCResult BrowserChild::RecvResumeLoad( 900 const uint64_t& aPendingSwitchID, const ParentShowInfo& aInfo) { 901 if (!mDidLoadURLInit) { 902 mDidLoadURLInit = true; 903 if (!InitBrowserChildMessageManager()) { 904 return IPC_FAIL_NO_REASON(this); 905 } 906 907 ApplyParentShowInfo(aInfo); 908 } 909 910 nsresult rv = WebNavigation()->ResumeRedirectedLoad(aPendingSwitchID, -1); 911 if (NS_FAILED(rv)) { 912 NS_WARNING("WebNavigation()->ResumeRedirectedLoad failed"); 913 } 914 915 return IPC_OK(); 916 } 917 918 nsresult BrowserChild::CloneDocumentTreeIntoSelf( 919 const MaybeDiscarded<BrowsingContext>& aSourceBC, 920 const embedding::PrintData& aPrintData) { 921 #ifdef NS_PRINTING 922 if (NS_WARN_IF(aSourceBC.IsNullOrDiscarded())) { 923 return NS_ERROR_FAILURE; 924 } 925 nsCOMPtr<Document> sourceDocument = aSourceBC.get()->GetDocument(); 926 if (NS_WARN_IF(!sourceDocument)) { 927 return NS_ERROR_FAILURE; 928 } 929 930 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation()); 931 if (NS_WARN_IF(!ourDocShell)) { 932 return NS_ERROR_FAILURE; 933 } 934 935 nsCOMPtr<nsIDocumentViewer> viewer; 936 ourDocShell->GetDocViewer(getter_AddRefs(viewer)); 937 if (NS_WARN_IF(!viewer)) { 938 return NS_ERROR_FAILURE; 939 } 940 941 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc = 942 do_GetService("@mozilla.org/gfx/printsettings-service;1"); 943 if (NS_WARN_IF(!printSettingsSvc)) { 944 return NS_ERROR_FAILURE; 945 } 946 947 nsCOMPtr<nsIPrintSettings> printSettings; 948 nsresult rv = 949 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings)); 950 if (NS_WARN_IF(NS_FAILED(rv))) { 951 return rv; 952 } 953 954 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings); 955 956 RefPtr<Document> clone; 957 { 958 AutoPrintEventDispatcher dispatcher(*sourceDocument); 959 nsAutoScriptBlocker scriptBlocker; 960 bool hasInProcessCallbacks = false; 961 clone = sourceDocument->CreateStaticClone( 962 ourDocShell, viewer, printSettings, &hasInProcessCallbacks); 963 if (NS_WARN_IF(!clone)) { 964 return NS_ERROR_FAILURE; 965 } 966 } 967 968 rv = UpdateRemotePrintSettings(aPrintData); 969 if (NS_FAILED(rv)) { 970 return rv; 971 } 972 973 #endif 974 return NS_OK; 975 } 976 977 mozilla::ipc::IPCResult BrowserChild::RecvCloneDocumentTreeIntoSelf( 978 const MaybeDiscarded<BrowsingContext>& aSourceBC, 979 const embedding::PrintData& aPrintData, 980 CloneDocumentTreeIntoSelfResolver&& aResolve) { 981 nsresult rv = NS_OK; 982 983 #ifdef NS_PRINTING 984 rv = CloneDocumentTreeIntoSelf(aSourceBC, aPrintData); 985 #endif 986 987 aResolve(NS_SUCCEEDED(rv)); 988 return IPC_OK(); 989 } 990 991 nsresult BrowserChild::UpdateRemotePrintSettings( 992 const embedding::PrintData& aPrintData) { 993 #ifdef NS_PRINTING 994 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation()); 995 if (NS_WARN_IF(!ourDocShell)) { 996 return NS_ERROR_FAILURE; 997 } 998 999 RefPtr<Document> doc = ourDocShell->GetExtantDocument(); 1000 if (NS_WARN_IF(!doc) || NS_WARN_IF(!doc->IsStaticDocument())) { 1001 return NS_ERROR_FAILURE; 1002 } 1003 1004 RefPtr<BrowsingContext> bc = ourDocShell->GetBrowsingContext(); 1005 if (NS_WARN_IF(!bc)) { 1006 return NS_ERROR_FAILURE; 1007 } 1008 1009 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc = 1010 do_GetService("@mozilla.org/gfx/printsettings-service;1"); 1011 if (NS_WARN_IF(!printSettingsSvc)) { 1012 return NS_ERROR_FAILURE; 1013 } 1014 1015 nsCOMPtr<nsIPrintSettings> printSettings; 1016 nsresult rv = 1017 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings)); 1018 if (NS_WARN_IF(NS_FAILED(rv))) { 1019 return rv; 1020 } 1021 1022 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings); 1023 1024 bc->PreOrderWalk([&](BrowsingContext* aBc) { 1025 if (nsCOMPtr<nsIDocShell> inProcess = aBc->GetDocShell()) { 1026 nsCOMPtr<nsIDocumentViewer> viewer; 1027 inProcess->GetDocViewer(getter_AddRefs(viewer)); 1028 if (NS_WARN_IF(!viewer)) { 1029 return BrowsingContext::WalkFlag::Skip; 1030 } 1031 // The CanRunScript analysis is not smart enough to see across 1032 // the std::function PreOrderWalk uses, so we cheat a bit here, but it is 1033 // fine because PreOrderWalk does deal with arbitrary script changing the 1034 // BC tree, and our code above is simple enough and keeps strong refs to 1035 // everything. 1036 ([&]() MOZ_CAN_RUN_SCRIPT_BOUNDARY { 1037 RefPtr<RemotePrintJobChild> printJob = 1038 static_cast<RemotePrintJobChild*>( 1039 aPrintData.remotePrintJob().AsChild()); 1040 viewer->SetPrintSettingsForSubdocument(printSettings, printJob); 1041 }()); 1042 } else if (RefPtr<BrowserBridgeChild> remoteChild = 1043 BrowserBridgeChild::GetFrom(aBc->GetEmbedderElement())) { 1044 (void)remoteChild->SendUpdateRemotePrintSettings(aPrintData); 1045 return BrowsingContext::WalkFlag::Skip; 1046 } 1047 return BrowsingContext::WalkFlag::Next; 1048 }); 1049 #endif 1050 1051 return NS_OK; 1052 } 1053 1054 mozilla::ipc::IPCResult BrowserChild::RecvUpdateRemotePrintSettings( 1055 const embedding::PrintData& aPrintData) { 1056 #ifdef NS_PRINTING 1057 UpdateRemotePrintSettings(aPrintData); 1058 #endif 1059 1060 return IPC_OK(); 1061 } 1062 1063 void BrowserChild::DoFakeShow(const ParentShowInfo& aParentShowInfo) { 1064 OwnerShowInfo ownerInfo{LayoutDeviceIntSize(), ScrollbarPreference::Auto, 1065 nsSizeMode_Normal}; 1066 RecvShow(aParentShowInfo, ownerInfo); 1067 mDidFakeShow = true; 1068 } 1069 1070 void BrowserChild::ApplyParentShowInfo(const ParentShowInfo& aInfo) { 1071 // Even if we already set real show info, the dpi / rounding & scale may still 1072 // be invalid (if BrowserParent wasn't able to get widget it would just send 1073 // 0). So better to always set up-to-date values here. 1074 if (aInfo.dpi() > 0) { 1075 mPuppetWidget->UpdateBackingScaleCache(aInfo.dpi(), aInfo.widgetRounding(), 1076 aInfo.defaultScale()); 1077 } 1078 1079 if (mDidSetRealShowInfo) { 1080 return; 1081 } 1082 1083 if (!aInfo.fakeShowInfo()) { 1084 // Once we've got one ShowInfo from parent, no need to update the values 1085 // anymore. 1086 mDidSetRealShowInfo = true; 1087 } 1088 1089 mIsTransparent = aInfo.isTransparent(); 1090 } 1091 1092 mozilla::ipc::IPCResult BrowserChild::RecvShow( 1093 const ParentShowInfo& aParentInfo, const OwnerShowInfo& aOwnerInfo) { 1094 bool res = true; 1095 1096 mPuppetWidget->SetSizeMode(aOwnerInfo.sizeMode()); 1097 if (!mDidFakeShow) { 1098 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation()); 1099 if (!baseWindow) { 1100 NS_ERROR("WebNavigation() doesn't QI to nsIBaseWindow"); 1101 return IPC_FAIL_NO_REASON(this); 1102 } 1103 1104 baseWindow->SetVisibility(true); 1105 res = InitBrowserChildMessageManager(); 1106 } 1107 1108 ApplyParentShowInfo(aParentInfo); 1109 1110 if (!mIsTopLevel) { 1111 RecvScrollbarPreferenceChanged(aOwnerInfo.scrollbarPreference()); 1112 } 1113 1114 if (!res) { 1115 return IPC_FAIL_NO_REASON(this); 1116 } 1117 1118 UpdateVisibility(); 1119 1120 return IPC_OK(); 1121 } 1122 1123 mozilla::ipc::IPCResult BrowserChild::RecvInitRendering( 1124 const TextureFactoryIdentifier& aTextureFactoryIdentifier, 1125 const layers::LayersId& aLayersId, 1126 const CompositorOptions& aCompositorOptions, const bool& aLayersConnected) { 1127 mLayersConnected = Some(aLayersConnected); 1128 mLayersConnectRequested = Some(aLayersConnected); 1129 InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions); 1130 return IPC_OK(); 1131 } 1132 1133 mozilla::ipc::IPCResult BrowserChild::RecvScrollbarPreferenceChanged( 1134 ScrollbarPreference aPreference) { 1135 MOZ_ASSERT(!mIsTopLevel, 1136 "Scrollbar visibility should be derived from chrome flags for " 1137 "top-level windows"); 1138 if (nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation())) { 1139 nsDocShell::Cast(docShell)->SetScrollbarPreference(aPreference); 1140 } 1141 return IPC_OK(); 1142 } 1143 1144 mozilla::ipc::IPCResult BrowserChild::RecvCompositorOptionsChanged( 1145 const CompositorOptions& aNewOptions) { 1146 MOZ_ASSERT(mCompositorOptions); 1147 1148 // The only compositor option we currently support changing is APZ 1149 // enablement. Even that is only partially supported for now: 1150 // * Going from APZ to non-APZ is fine - we just flip the stored flag. 1151 // Note that we keep the actors (mApzcTreeManager, and the APZChild 1152 // created in InitAPZState()) around (read on for why). 1153 // * Going from non-APZ to APZ is only supported if we were using 1154 // APZ initially (at InitRendering() time) and we are transitioning 1155 // back. In this case, we just reuse the actors which we kept around. 1156 // Fully supporting a non-APZ to APZ transition (i.e. even in cases 1157 // where we initialized as non-APZ) would require setting up the actors 1158 // here. (In that case, we would also have the options of destroying 1159 // the actors in the APZ --> non-APZ case, and always re-creating them 1160 // during a non-APZ --> APZ transition). 1161 mCompositorOptions->SetUseAPZ(aNewOptions.UseAPZ()); 1162 return IPC_OK(); 1163 } 1164 1165 mozilla::ipc::IPCResult BrowserChild::RecvUpdateDimensions( 1166 const DimensionInfo& aDimensionInfo) { 1167 if (mLayersConnected.isNothing()) { 1168 return IPC_OK(); 1169 } 1170 1171 mUnscaledOuterRect = aDimensionInfo.rect(); 1172 mClientOffset = aDimensionInfo.clientOffset(); 1173 mChromeOffset = aDimensionInfo.chromeOffset(); 1174 MOZ_ASSERT_IF(!IsTopLevel(), mChromeOffset == LayoutDeviceIntPoint()); 1175 1176 SetUnscaledInnerSize(aDimensionInfo.size()); 1177 if (!mHasValidInnerSize && aDimensionInfo.size().width != 0 && 1178 aDimensionInfo.size().height != 0) { 1179 mHasValidInnerSize = true; 1180 } 1181 1182 const LayoutDeviceIntSize innerSize = GetInnerSize(); 1183 // Make sure to set the size on the document viewer first. The 1184 // MobileViewportManager needs the content viewer size to be updated before 1185 // the reflow, otherwise it gets a stale size when it computes a new CSS 1186 // viewport. 1187 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation()); 1188 baseWin->SetPositionAndSize(0, 0, innerSize.width, innerSize.height, 1189 nsIBaseWindow::eRepaint); 1190 1191 const LayoutDeviceIntRect widgetRect( 1192 GetOuterRect().TopLeft() + mClientOffset + mChromeOffset, innerSize); 1193 mPuppetWidget->Resize(widgetRect / mPuppetWidget->GetDesktopToDeviceScale(), 1194 true); 1195 1196 RecvSafeAreaInsetsChanged(mPuppetWidget->GetSafeAreaInsets()); 1197 1198 return IPC_OK(); 1199 } 1200 1201 mozilla::ipc::IPCResult BrowserChild::RecvSizeModeChanged( 1202 const nsSizeMode& aSizeMode) { 1203 mPuppetWidget->SetSizeMode(aSizeMode); 1204 if (!mPuppetWidget->IsVisible()) { 1205 return IPC_OK(); 1206 } 1207 nsCOMPtr<Document> document(GetTopLevelDocument()); 1208 if (!document) { 1209 return IPC_OK(); 1210 } 1211 nsPresContext* presContext = document->GetPresContext(); 1212 if (presContext) { 1213 presContext->SizeModeChanged(aSizeMode); 1214 } 1215 return IPC_OK(); 1216 } 1217 1218 mozilla::ipc::IPCResult BrowserChild::RecvChildToParentMatrix( 1219 const Maybe<gfx::Matrix4x4>& aMatrix, 1220 const ScreenRect& aTopLevelViewportVisibleRectInBrowserCoords) { 1221 mChildToParentConversionMatrix = 1222 LayoutDeviceToLayoutDeviceMatrix4x4::FromUnknownMatrix(aMatrix); 1223 mTopLevelViewportVisibleRectInBrowserCoords = 1224 aTopLevelViewportVisibleRectInBrowserCoords; 1225 1226 if (mContentTransformPromise) { 1227 mContentTransformPromise->MaybeResolveWithUndefined(); 1228 mContentTransformPromise = nullptr; 1229 } 1230 1231 // Trigger an intersection observation update since ancestor viewports 1232 // changed. 1233 if (RefPtr<Document> toplevelDoc = GetTopLevelDocument()) { 1234 if (nsPresContext* pc = toplevelDoc->GetPresContext()) { 1235 pc->RefreshDriver()->EnsureIntersectionObservationsUpdateHappens(); 1236 } 1237 } 1238 1239 return IPC_OK(); 1240 } 1241 1242 mozilla::ipc::IPCResult BrowserChild::RecvUpdateRemoteStyle( 1243 const StyleImageRendering& aImageRendering) { 1244 BrowsingContext* context = GetBrowsingContext(); 1245 if (!context) { 1246 return IPC_OK(); 1247 } 1248 1249 Document* document = context->GetDocument(); 1250 if (!document) { 1251 return IPC_OK(); 1252 } 1253 1254 if (document->IsImageDocument()) { 1255 document->AsImageDocument()->UpdateRemoteStyle(aImageRendering); 1256 } 1257 1258 return IPC_OK(); 1259 } 1260 1261 mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarMaxHeightChanged( 1262 const ScreenIntCoord& aHeight) { 1263 mDynamicToolbarMaxHeight = aHeight; 1264 1265 RefPtr<Document> document = GetTopLevelDocument(); 1266 if (!document) { 1267 return IPC_OK(); 1268 } 1269 1270 if (RefPtr<nsPresContext> presContext = document->GetPresContext()) { 1271 presContext->SetDynamicToolbarMaxHeight(aHeight); 1272 } 1273 return IPC_OK(); 1274 } 1275 1276 mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarOffsetChanged( 1277 const ScreenIntCoord& aOffset) { 1278 RefPtr<Document> document = GetTopLevelDocument(); 1279 if (!document) { 1280 return IPC_OK(); 1281 } 1282 1283 if (nsPresContext* presContext = document->GetPresContext()) { 1284 presContext->UpdateDynamicToolbarOffset(aOffset); 1285 } 1286 return IPC_OK(); 1287 } 1288 1289 mozilla::ipc::IPCResult BrowserChild::RecvKeyboardHeightChanged( 1290 const ScreenIntCoord& aHeight) { 1291 #if defined(MOZ_WIDGET_ANDROID) 1292 mKeyboardHeight = aHeight; 1293 1294 RefPtr<Document> document = GetTopLevelDocument(); 1295 if (!document) { 1296 return IPC_OK(); 1297 } 1298 1299 if (nsPresContext* presContext = document->GetPresContext()) { 1300 presContext->UpdateKeyboardHeight(aHeight); 1301 } 1302 #endif 1303 return IPC_OK(); 1304 } 1305 1306 mozilla::ipc::IPCResult BrowserChild::RecvAndroidPipModeChanged(bool aPipMode) { 1307 if (mInAndroidPipMode == aPipMode) { 1308 return IPC_OK(); 1309 } 1310 mInAndroidPipMode = aPipMode; 1311 if (RefPtr<Document> document = GetTopLevelDocument()) { 1312 if (nsPresContext* presContext = document->GetPresContext()) { 1313 presContext->MediaFeatureValuesChanged( 1314 {MediaFeatureChangeReason::DisplayModeChange}, 1315 MediaFeatureChangePropagation::JustThisDocument); 1316 } 1317 nsContentUtils::DispatchEventOnlyToChrome( 1318 document, document, 1319 aPipMode ? u"MozAndroidPipModeEntered"_ns 1320 : u"MozAndroidPipModeExited"_ns, 1321 CanBubble::eYes, Cancelable::eNo, /* DefaultAction */ nullptr); 1322 } 1323 return IPC_OK(); 1324 } 1325 1326 mozilla::ipc::IPCResult BrowserChild::RecvSuppressDisplayport( 1327 const bool& aEnabled) { 1328 if (RefPtr<PresShell> presShell = GetTopLevelPresShell()) { 1329 presShell->SuppressDisplayport(aEnabled); 1330 } 1331 return IPC_OK(); 1332 } 1333 1334 void BrowserChild::HandleDoubleTap(const CSSPoint& aPoint, 1335 const Modifiers& aModifiers, 1336 const ScrollableLayerGuid& aGuid, 1337 const DoubleTapToZoomMetrics& aMetrics) { 1338 MOZ_LOG( 1339 sApzChildLog, LogLevel::Debug, 1340 ("Handling double tap at %s with %p %p\n", ToString(aPoint).c_str(), 1341 mBrowserChildMessageManager ? mBrowserChildMessageManager->GetWrapper() 1342 : nullptr, 1343 mBrowserChildMessageManager.get())); 1344 1345 if (!mBrowserChildMessageManager) { 1346 return; 1347 } 1348 1349 // Note: there is nothing to do with the modifiers here, as we are not 1350 // synthesizing any sort of mouse event. 1351 RefPtr<Document> document = GetTopLevelDocument(); 1352 ZoomTarget zoomTarget = CalculateRectToZoomTo(document, aPoint, aMetrics); 1353 // The double-tap can be dispatched by any scroll frame (so |aGuid| could be 1354 // the guid of any scroll frame), but the zoom-to-rect operation must be 1355 // performed by the root content scroll frame, so query its identifiers 1356 // for the SendZoomToRect() call rather than using the ones from |aGuid|. 1357 uint32_t presShellId; 1358 ViewID viewId; 1359 if (APZCCallbackHelper::GetOrCreateScrollIdentifiers( 1360 document->GetDocumentElement(), &presShellId, &viewId) && 1361 mApzcTreeManager) { 1362 ScrollableLayerGuid guid(mLayersId, presShellId, viewId); 1363 1364 mApzcTreeManager->ZoomToRect(guid, zoomTarget, 1365 ZoomToRectBehavior::DEFAULT_BEHAVIOR); 1366 } 1367 } 1368 1369 mozilla::ipc::IPCResult BrowserChild::RecvHandleTap( 1370 const GeckoContentController::TapType& aType, 1371 const LayoutDevicePoint& aPoint, const Modifiers& aModifiers, 1372 const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId, 1373 const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) { 1374 // IPDL doesn't hold a strong reference to protocols as they're not required 1375 // to be refcounted. This function can run script, which may trigger a nested 1376 // event loop, which may release this, so we hold a strong reference here. 1377 RefPtr<BrowserChild> kungFuDeathGrip(this); 1378 RefPtr<PresShell> presShell = GetTopLevelPresShell(); 1379 if (!presShell || !presShell->GetPresContext() || !mAPZEventState) { 1380 return IPC_OK(); 1381 } 1382 CSSToLayoutDeviceScale scale( 1383 presShell->GetPresContext()->CSSToDevPixelScale()); 1384 CSSPoint point = aPoint / scale; 1385 1386 // Stash the guid in InputAPZContext so that when the visual-to-layout 1387 // transform is applied to the event's coordinates, we use the right transform 1388 // based on the scroll frame being targeted. 1389 // The other values don't really matter. 1390 InputAPZContext context(aGuid, aInputBlockId, nsEventStatus_eSentinel); 1391 1392 switch (aType) { 1393 case GeckoContentController::TapType::eSingleTap: 1394 if (mBrowserChildMessageManager) { 1395 RefPtr<APZEventState> eventState(mAPZEventState); 1396 eventState->ProcessSingleTap(point, scale, aModifiers, 1, 1397 aInputBlockId); 1398 } 1399 break; 1400 case GeckoContentController::TapType::eDoubleTap: 1401 HandleDoubleTap(point, aModifiers, aGuid, *aDoubleTapToZoomMetrics); 1402 break; 1403 case GeckoContentController::TapType::eSecondTap: 1404 if (mBrowserChildMessageManager) { 1405 RefPtr<APZEventState> eventState(mAPZEventState); 1406 eventState->ProcessSingleTap(point, scale, aModifiers, 2, 1407 aInputBlockId); 1408 } 1409 break; 1410 case GeckoContentController::TapType::eLongTap: 1411 if (mBrowserChildMessageManager) { 1412 RefPtr<APZEventState> eventState(mAPZEventState); 1413 eventState->ProcessLongTap(presShell, point, scale, aModifiers, 1414 aInputBlockId); 1415 } 1416 break; 1417 case GeckoContentController::TapType::eLongTapUp: 1418 if (mBrowserChildMessageManager) { 1419 RefPtr<APZEventState> eventState(mAPZEventState); 1420 eventState->ProcessLongTapUp(presShell, point, scale, aModifiers); 1421 } 1422 break; 1423 } 1424 1425 // mAPZEventState may not dispatch the compatibility mouse events. Therefore, 1426 // we should release the pointer capturing element at the last ePointerUp 1427 // here. 1428 PointerEventHandler::ReleasePointerCapturingElementAtLastPointerUp(); 1429 1430 return IPC_OK(); 1431 } 1432 1433 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityHandleTap( 1434 const GeckoContentController::TapType& aType, 1435 const LayoutDevicePoint& aPoint, const Modifiers& aModifiers, 1436 const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId, 1437 const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) { 1438 // IPDL doesn't hold a strong reference to protocols as they're not required 1439 // to be refcounted. This function can run script, which may trigger a nested 1440 // event loop, which may release this, so we hold a strong reference here. 1441 RefPtr<BrowserChild> kungFuDeathGrip(this); 1442 return RecvHandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId, 1443 aDoubleTapToZoomMetrics); 1444 } 1445 1446 void BrowserChild::NotifyAPZStateChange( 1447 const ViewID& aViewId, 1448 const layers::GeckoContentController::APZStateChange& aChange, 1449 const int& aArg, Maybe<uint64_t> aInputBlockId) { 1450 if (mAPZEventState) { 1451 mAPZEventState->ProcessAPZStateChange(aViewId, aChange, aArg, 1452 aInputBlockId); 1453 } 1454 nsCOMPtr<nsIObserverService> observerService = 1455 mozilla::services::GetObserverService(); 1456 if (aChange == 1457 layers::GeckoContentController::APZStateChange::eTransformEnd) { 1458 // This is used by tests to determine when the APZ is done doing whatever 1459 // it's doing. XXX generify this as needed when writing additional tests. 1460 observerService->NotifyObservers(nullptr, "APZ:TransformEnd", nullptr); 1461 observerService->NotifyObservers(nullptr, "PanZoom:StateChange", 1462 u"NOTHING"); 1463 } else if (aChange == 1464 layers::GeckoContentController::APZStateChange::eTransformBegin) { 1465 observerService->NotifyObservers(nullptr, "PanZoom:StateChange", 1466 u"PANNING"); 1467 } 1468 } 1469 1470 void BrowserChild::StartScrollbarDrag( 1471 const layers::AsyncDragMetrics& aDragMetrics) { 1472 ScrollableLayerGuid guid(mLayersId, aDragMetrics.mPresShellId, 1473 aDragMetrics.mViewId); 1474 1475 if (mApzcTreeManager) { 1476 mApzcTreeManager->StartScrollbarDrag(guid, aDragMetrics); 1477 } 1478 } 1479 1480 void BrowserChild::ZoomToRect(const uint32_t& aPresShellId, 1481 const ScrollableLayerGuid::ViewID& aViewId, 1482 const CSSRect& aRect, const uint32_t& aFlags) { 1483 ScrollableLayerGuid guid(mLayersId, aPresShellId, aViewId); 1484 1485 if (mApzcTreeManager) { 1486 mApzcTreeManager->ZoomToRect(guid, ZoomTarget{aRect}, aFlags); 1487 } 1488 } 1489 1490 mozilla::ipc::IPCResult BrowserChild::RecvActivate(uint64_t aActionId) { 1491 MOZ_ASSERT(mWebBrowser); 1492 mWebBrowser->FocusActivate(aActionId); 1493 return IPC_OK(); 1494 } 1495 1496 mozilla::ipc::IPCResult BrowserChild::RecvDeactivate(uint64_t aActionId) { 1497 MOZ_ASSERT(mWebBrowser); 1498 mWebBrowser->FocusDeactivate(aActionId); 1499 return IPC_OK(); 1500 } 1501 1502 mozilla::ipc::IPCResult BrowserChild::RecvStopIMEStateManagement() { 1503 IMEStateManager::StopIMEStateManagement(); 1504 return IPC_OK(); 1505 } 1506 1507 void BrowserChild::ProcessPendingCoalescedTouchData() { 1508 MOZ_ASSERT(StaticPrefs::dom_events_coalesce_touchmove()); 1509 1510 if (mCoalescedTouchData.IsEmpty()) { 1511 return; 1512 } 1513 1514 if (mCoalescedTouchMoveEventFlusher) { 1515 mCoalescedTouchMoveEventFlusher->RemoveObserver(); 1516 } 1517 1518 UniquePtr<WidgetTouchEvent> touchMoveEvent = 1519 mCoalescedTouchData.TakeCoalescedEvent(); 1520 (void)RecvRealTouchEvent(*touchMoveEvent, 1521 mCoalescedTouchData.GetScrollableLayerGuid(), 1522 mCoalescedTouchData.GetInputBlockId(), 1523 mCoalescedTouchData.GetApzResponse()); 1524 } 1525 1526 void BrowserChild::ProcessPendingCoalescedMouseDataAndDispatchEvents() { 1527 if (!mCoalesceMouseMoveEvents || !mCoalescedMouseEventFlusher) { 1528 // We don't enable mouse coalescing or we are destroying BrowserChild. 1529 return; 1530 } 1531 1532 // We may reentry the event loop and push more data to 1533 // mToBeDispatchedMouseData while dispatching an event. 1534 1535 // We may have some pending coalesced data while dispatch an event and reentry 1536 // the event loop. In that case we don't have chance to consume the remaining 1537 // pending data until we get new mouse events. Get some helps from 1538 // mCoalescedMouseEventFlusher to trigger it. 1539 mCoalescedMouseEventFlusher->StartObserver(); 1540 1541 while (mToBeDispatchedMouseData.GetSize() > 0) { 1542 UniquePtr<CoalescedMouseData> data( 1543 static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront())); 1544 1545 UniquePtr<WidgetMouseEvent> event = data->TakeCoalescedEvent(); 1546 if (event) { 1547 // When the real mouse event receivers put the received event into the 1548 // queue, they should dispatch eMouseRawUpdate event immediately (if and 1549 // only if it's required). Therefore, unless the event is the last one 1550 // of the queue, the pending events should've been marked as "Do not 1551 // convert to "pointerrawupdate". 1552 MOZ_ASSERT_IF(mToBeDispatchedMouseData.GetSize() > 0, 1553 !event->convertToPointerRawUpdate); 1554 // Dispatch the pending events. Using HandleRealMouseButtonEvent 1555 // to bypass the coalesce handling in RecvRealMouseMoveEvent. Can't use 1556 // RecvRealMouseButtonEvent because we may also put some mouse events 1557 // other than mousemove. 1558 HandleRealMouseButtonEvent(*event, data->GetScrollableLayerGuid(), 1559 data->GetInputBlockId()); 1560 } 1561 } 1562 // mCoalescedMouseEventFlusher may be destroyed when reentrying the event 1563 // loop. 1564 if (mCoalescedMouseEventFlusher) { 1565 mCoalescedMouseEventFlusher->RemoveObserver(); 1566 } 1567 } 1568 1569 LayoutDeviceToLayoutDeviceMatrix4x4 1570 BrowserChild::GetChildToParentConversionMatrix() const { 1571 if (mChildToParentConversionMatrix) { 1572 return *mChildToParentConversionMatrix; 1573 } 1574 LayoutDevicePoint offset(GetChromeOffset()); 1575 return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset); 1576 } 1577 1578 Maybe<ScreenRect> BrowserChild::GetTopLevelViewportVisibleRectInBrowserCoords() 1579 const { 1580 if (!mChildToParentConversionMatrix) { 1581 return Nothing(); 1582 } 1583 return Some(mTopLevelViewportVisibleRectInBrowserCoords); 1584 } 1585 1586 void BrowserChild::FlushAllCoalescedMouseData() { 1587 MOZ_ASSERT(mCoalesceMouseMoveEvents); 1588 1589 // Move all entries from mCoalescedMouseData to mToBeDispatchedMouseData. 1590 for (const auto& data : mCoalescedMouseData.Values()) { 1591 if (!data || data->IsEmpty()) { 1592 continue; 1593 } 1594 UniquePtr<CoalescedMouseData> dispatchData = 1595 MakeUnique<CoalescedMouseData>(); 1596 1597 dispatchData->RetrieveDataFrom(*data); 1598 mToBeDispatchedMouseData.Push(dispatchData.release()); 1599 } 1600 mCoalescedMouseData.Clear(); 1601 } 1602 1603 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseMoveEvent( 1604 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1605 const uint64_t& aInputBlockId) { 1606 if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher) { 1607 CoalescedMouseData* data = 1608 mCoalescedMouseData.GetOrInsertNew(aEvent.pointerId); 1609 MOZ_ASSERT(data); 1610 if (data->CanCoalesce(aEvent, aGuid, aInputBlockId, 1611 mCoalescedMouseEventFlusher->GetRefreshDriver())) { 1612 // Callback doesn't support if the event is coalesced. 1613 MOZ_ASSERT_IF(!data->IsEmpty(), aEvent.mCallbackId.isNothing()); 1614 1615 // We don't need to dispatch aEvent immediately. However, we need to 1616 // dispatch eMouseRawUpdate immediately if there is a `pointerrawupdate` 1617 // event listener. Therefore, the cloned event in the queue shouldn't 1618 // cause eMouseRawUpdate later when it'll be dispatched. 1619 WidgetMouseEvent pendingMouseMoveEvent(aEvent); 1620 // We don't want to dispatch aEvent immediately, so the cloned event 1621 // should track the cllback id. And the callback id of cloned event will 1622 // be moved again if there is no coalesced data yet when coalescing. 1623 pendingMouseMoveEvent.mCallbackId = std::move(aEvent.mCallbackId); 1624 pendingMouseMoveEvent.convertToPointerRawUpdate = false; 1625 data->Coalesce(pendingMouseMoveEvent, aGuid, aInputBlockId); 1626 mCoalescedMouseEventFlusher->StartObserver(); 1627 HandleMouseRawUpdateEvent(pendingMouseMoveEvent, aGuid, aInputBlockId); 1628 return IPC_OK(); 1629 } 1630 1631 // Can't coalesce current mousemove event. Put the coalesced mousemove data 1632 // with the same pointer id to mToBeDispatchedMouseData, coalesce the 1633 // current one, and process all pending data in mToBeDispatchedMouseData. 1634 UniquePtr<CoalescedMouseData> dispatchData = 1635 MakeUnique<CoalescedMouseData>(); 1636 1637 dispatchData->RetrieveDataFrom(*data); 1638 mToBeDispatchedMouseData.Push(dispatchData.release()); 1639 1640 // Put new data to replace the old one in the hash table. 1641 CoalescedMouseData* newData = 1642 mCoalescedMouseData 1643 .InsertOrUpdate(aEvent.pointerId, MakeUnique<CoalescedMouseData>()) 1644 .get(); 1645 // We don't want to dispatch aEvent immediately. However, we need to 1646 // dispatch eMouseRawUpdate immediately if there is a `pointerrawupdate` 1647 // event listener. Therefore, the cloned event in the queue shouldn't 1648 // cause eMouseRawUpdate later when it'll be dispatched. 1649 WidgetMouseEvent pendingMouseMoveEvent(aEvent); 1650 // The cloned event should track the cllback id. And the callback id of 1651 // cloned event will be moved again if there is no coalesced data yet when 1652 // coalescing. 1653 pendingMouseMoveEvent.mCallbackId = std::move(aEvent.mCallbackId); 1654 pendingMouseMoveEvent.convertToPointerRawUpdate = false; 1655 newData->Coalesce(pendingMouseMoveEvent, aGuid, aInputBlockId); 1656 1657 // Dispatch all pending mouse events which does NOT include aEvent. 1658 ProcessPendingCoalescedMouseDataAndDispatchEvents(); 1659 1660 mCoalescedMouseEventFlusher->StartObserver(); 1661 // Finally, dispatch eMouseRawUpdate for aEvent right now. 1662 HandleMouseRawUpdateEvent(pendingMouseMoveEvent, aGuid, aInputBlockId); 1663 return IPC_OK(); 1664 } 1665 1666 if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) { 1667 return IPC_FAIL_NO_REASON(this); 1668 } 1669 return IPC_OK(); 1670 } 1671 1672 void BrowserChild::HandleMouseRawUpdateEvent( 1673 const WidgetMouseEvent& aPendingMouseEvent, 1674 const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId) { 1675 // If there is no window containing pointerrawupdate event listeners or the 1676 // event is a synthesized mousemove, we don't need to dispatch eMouseRawUpdate 1677 // event. 1678 if (!mPointerRawUpdateWindowCount || aPendingMouseEvent.IsSynthesized()) { 1679 return; 1680 } 1681 WidgetMouseEvent mouseRawUpdateEvent(aPendingMouseEvent); 1682 mouseRawUpdateEvent.mMessage = eMouseRawUpdate; 1683 // PointerEvent.button should always be -1 if the source event is eMouseMove. 1684 // PointerEventHandler cannot distinguish whether it's caused by 1685 // eMouseDown/eMouseUp or eMouseMove. Therefore, we need to set -1 1686 // (eNotPressed) here. 1687 mouseRawUpdateEvent.mButton = MouseButton::eNotPressed; 1688 mouseRawUpdateEvent.mCoalescedWidgetEvents = nullptr; 1689 mouseRawUpdateEvent.convertToPointer = true; 1690 // Nobody checks `convertToPointerRawUpdate` of eMouseRawUpdate event. 1691 // However, the name indicates that it would cause ePointerRawUpdate. 1692 // For avoiding to make the developers who watch the value with the debugger 1693 // confused, here sets it to `true`. 1694 mouseRawUpdateEvent.convertToPointerRawUpdate = true; 1695 HandleRealMouseButtonEvent(mouseRawUpdateEvent, aGuid, aInputBlockId); 1696 } 1697 1698 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseMoveEventForTests( 1699 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1700 const uint64_t& aInputBlockId) { 1701 return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId); 1702 } 1703 1704 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseMoveEvent( 1705 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1706 const uint64_t& aInputBlockId) { 1707 return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId); 1708 } 1709 1710 mozilla::ipc::IPCResult 1711 BrowserChild::RecvNormalPriorityRealMouseMoveEventForTests( 1712 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1713 const uint64_t& aInputBlockId) { 1714 return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId); 1715 } 1716 1717 mozilla::ipc::IPCResult BrowserChild::RecvSynthMouseMoveEvent( 1718 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1719 const uint64_t& aInputBlockId) { 1720 if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) { 1721 return IPC_FAIL_NO_REASON(this); 1722 } 1723 return IPC_OK(); 1724 } 1725 1726 mozilla::ipc::IPCResult BrowserChild::RecvNormalPrioritySynthMouseMoveEvent( 1727 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1728 const uint64_t& aInputBlockId) { 1729 return RecvSynthMouseMoveEvent(aEvent, aGuid, aInputBlockId); 1730 } 1731 1732 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseButtonEvent( 1733 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1734 const uint64_t& aInputBlockId) { 1735 if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher && 1736 aEvent.mMessage != eMouseMove) { 1737 // When receiving a mouse event other than mousemove, we have to dispatch 1738 // all coalesced events before it. However, we can't dispatch all pending 1739 // coalesced events directly because we may reentry the event loop while 1740 // dispatching. To make sure we won't dispatch disorder events, we move all 1741 // coalesced mousemove events and current event to a deque to dispatch them. 1742 // When reentrying the event loop and dispatching more events, we put new 1743 // events in the end of the nsQueue and dispatch events from the beginning. 1744 FlushAllCoalescedMouseData(); 1745 1746 UniquePtr<CoalescedMouseData> dispatchData = 1747 MakeUnique<CoalescedMouseData>(); 1748 1749 // We'll dispatch aEvent immediately via 1750 // ProcessPendingCoalescedMouseDataAndDispatchEvents(). 1751 // Therefore, PresShell should convert it to eMouseRawUpdate when it starts 1752 // handling aEvent if and only if there is a `pointerrawupdate` event 1753 // listener. Therefore, let's assert the allowing flag to convert it to 1754 // eMouseRawUpdate here. 1755 MOZ_ASSERT(aEvent.convertToPointerRawUpdate); 1756 dispatchData->Coalesce(aEvent, aGuid, aInputBlockId); 1757 1758 mToBeDispatchedMouseData.Push(dispatchData.release()); 1759 ProcessPendingCoalescedMouseDataAndDispatchEvents(); 1760 return IPC_OK(); 1761 } 1762 HandleRealMouseButtonEvent(aEvent, aGuid, aInputBlockId); 1763 return IPC_OK(); 1764 } 1765 1766 mozilla::ipc::IPCResult BrowserChild::RecvRealPointerButtonEvent( 1767 const WidgetPointerEvent& aEvent, const ScrollableLayerGuid& aGuid, 1768 const uint64_t& aInputBlockId) { 1769 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId); 1770 } 1771 1772 void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, 1773 const ScrollableLayerGuid& aGuid, 1774 const uint64_t& aInputBlockId) { 1775 AutoSynthesizedEventResponder<WidgetMouseEvent> responder(this, aEvent); 1776 1777 Maybe<WidgetPointerEvent> pointerEvent; 1778 Maybe<WidgetMouseEvent> mouseEvent; 1779 if (aEvent.mClass == ePointerEventClass) { 1780 pointerEvent.emplace(aEvent); 1781 } else { 1782 mouseEvent.emplace(aEvent); 1783 } 1784 WidgetMouseEvent& localEvent = 1785 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref(); 1786 localEvent.mWidget = mPuppetWidget; 1787 1788 // We need one InputAPZContext here to propagate |aGuid| to places in 1789 // SendSetTargetAPZCNotification() which apply the visual-to-layout transform, 1790 // and another below to propagate the |postLayerization| flag (whose value 1791 // we don't know until SendSetTargetAPZCNotification() returns) into 1792 // the event dispatch code. 1793 InputAPZContext context1(aGuid, aInputBlockId, nsEventStatus_eSentinel); 1794 1795 // Mouse events like eMouseEnterIntoWidget, that are created in the parent 1796 // process EventStateManager code, have an input block id which they get from 1797 // the InputAPZContext in the parent process stack. However, they did not 1798 // actually go through the APZ code and so their mHandledByAPZ flag is false. 1799 // Since thos events didn't go through APZ, we don't need to send 1800 // notifications for them. 1801 RefPtr<DisplayportSetListener> postLayerization; 1802 if (aInputBlockId && localEvent.mFlags.mHandledByAPZ) { 1803 nsCOMPtr<Document> document(GetTopLevelDocument()); 1804 postLayerization = APZCCallbackHelper::SendSetTargetAPZCNotification( 1805 mPuppetWidget, document, localEvent, aGuid.mLayersId, aInputBlockId); 1806 } 1807 1808 InputAPZContext context2(aGuid, aInputBlockId, nsEventStatus_eSentinel, 1809 postLayerization != nullptr); 1810 1811 DispatchWidgetEventViaAPZ(localEvent); 1812 1813 if (aInputBlockId && localEvent.mFlags.mHandledByAPZ && mAPZEventState) { 1814 mAPZEventState->ProcessMouseEvent(localEvent, aInputBlockId); 1815 } 1816 1817 // Do this after the DispatchWidgetEventViaAPZ call above, so that if the 1818 // mouse event triggered a post-refresh AsyncDragMetrics message to be sent 1819 // to APZ (from scrollbar dragging in nsSliderFrame), then that will reach 1820 // APZ before the SetTargetAPZC message. This ensures the drag input block 1821 // gets the drag metrics before handling the input events. 1822 if (postLayerization) { 1823 postLayerization->Register(); 1824 } 1825 } 1826 1827 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent( 1828 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1829 const uint64_t& aInputBlockId) { 1830 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId); 1831 } 1832 1833 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealPointerButtonEvent( 1834 const WidgetPointerEvent& aEvent, const ScrollableLayerGuid& aGuid, 1835 const uint64_t& aInputBlockId) { 1836 return RecvNormalPriorityRealMouseButtonEvent(aEvent, aGuid, aInputBlockId); 1837 } 1838 1839 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseEnterExitWidgetEvent( 1840 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1841 const uint64_t& aInputBlockId) { 1842 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId); 1843 } 1844 1845 mozilla::ipc::IPCResult 1846 BrowserChild::RecvNormalPriorityRealMouseEnterExitWidgetEvent( 1847 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid, 1848 const uint64_t& aInputBlockId) { 1849 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId); 1850 } 1851 1852 nsEventStatus BrowserChild::DispatchWidgetEventViaAPZ(WidgetGUIEvent& aEvent) { 1853 aEvent.ResetWaitingReplyFromRemoteProcessState(); 1854 return APZCCallbackHelper::DispatchWidgetEvent(aEvent); 1855 } 1856 1857 void BrowserChild::DispatchCoalescedWheelEvent() { 1858 UniquePtr<WidgetWheelEvent> wheelEvent = 1859 mCoalescedWheelData.TakeCoalescedEvent(); 1860 MOZ_ASSERT(wheelEvent); 1861 DispatchWheelEvent(*wheelEvent, mCoalescedWheelData.GetScrollableLayerGuid(), 1862 mCoalescedWheelData.GetInputBlockId()); 1863 } 1864 1865 void BrowserChild::DispatchWheelEvent(const WidgetWheelEvent& aEvent, 1866 const ScrollableLayerGuid& aGuid, 1867 const uint64_t& aInputBlockId) { 1868 WidgetWheelEvent localEvent(aEvent); 1869 if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) { 1870 nsCOMPtr<Document> document(GetTopLevelDocument()); 1871 RefPtr<DisplayportSetListener> postLayerization = 1872 APZCCallbackHelper::SendSetTargetAPZCNotification( 1873 mPuppetWidget, document, aEvent, aGuid.mLayersId, aInputBlockId); 1874 if (postLayerization) { 1875 postLayerization->Register(); 1876 } 1877 } 1878 1879 localEvent.mWidget = mPuppetWidget; 1880 1881 // Stash the guid in InputAPZContext so that when the visual-to-layout 1882 // transform is applied to the event's coordinates, we use the right transform 1883 // based on the scroll frame being targeted. 1884 // The other values don't really matter. 1885 InputAPZContext context(aGuid, aInputBlockId, nsEventStatus_eSentinel); 1886 1887 DispatchWidgetEventViaAPZ(localEvent); 1888 1889 if (localEvent.mCanTriggerSwipe) { 1890 SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe()); 1891 } 1892 1893 if (aInputBlockId && aEvent.mFlags.mHandledByAPZ && mAPZEventState) { 1894 mAPZEventState->ProcessWheelEvent(localEvent, aInputBlockId); 1895 } 1896 } 1897 1898 mozilla::ipc::IPCResult BrowserChild::RecvMouseWheelEvent( 1899 const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid, 1900 const uint64_t& aInputBlockId) { 1901 AutoSynthesizedEventResponder<WidgetWheelEvent> responder(this, aEvent); 1902 1903 bool isNextWheelEvent = false; 1904 // We only coalesce the current event when 1905 // 1. It's eWheel (we don't coalesce eOperationStart and eWheelOperationEnd) 1906 // 2. It has same attributes as the coalesced wheel event which is not yet 1907 // fired. 1908 if (aEvent.mMessage == eWheel) { 1909 GetIPCChannel()->PeekMessages( 1910 [&isNextWheelEvent](const IPC::Message& aMsg) -> bool { 1911 if (aMsg.type() == mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID) { 1912 isNextWheelEvent = true; 1913 } 1914 return false; // Stop peeking. 1915 }); 1916 1917 if (!mCoalescedWheelData.IsEmpty() && 1918 !mCoalescedWheelData.CanCoalesce(aEvent, aGuid, aInputBlockId)) { 1919 DispatchCoalescedWheelEvent(); 1920 MOZ_ASSERT(mCoalescedWheelData.IsEmpty()); 1921 } 1922 mCoalescedWheelData.Coalesce(aEvent, aGuid, aInputBlockId); 1923 1924 MOZ_ASSERT(!mCoalescedWheelData.IsEmpty()); 1925 // If the next event isn't a wheel event, make sure we dispatch. 1926 if (!isNextWheelEvent) { 1927 DispatchCoalescedWheelEvent(); 1928 } 1929 } else { 1930 DispatchWheelEvent(aEvent, aGuid, aInputBlockId); 1931 } 1932 1933 return IPC_OK(); 1934 } 1935 1936 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityMouseWheelEvent( 1937 const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid, 1938 const uint64_t& aInputBlockId) { 1939 return RecvMouseWheelEvent(aEvent, aGuid, aInputBlockId); 1940 } 1941 1942 mozilla::ipc::IPCResult BrowserChild::RecvRealTouchEvent( 1943 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid, 1944 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) { 1945 MOZ_LOG(sApzChildLog, LogLevel::Debug, 1946 ("Receiving touch event of type %d\n", aEvent.mMessage)); 1947 1948 if (StaticPrefs::dom_events_coalesce_touchmove()) { 1949 if (aEvent.mMessage == eTouchEnd || aEvent.mMessage == eTouchStart) { 1950 ProcessPendingCoalescedTouchData(); 1951 } 1952 1953 if (aEvent.mMessage != eTouchMove && aEvent.mMessage != eTouchRawUpdate) { 1954 sConsecutiveTouchMoveCount = 0; 1955 } 1956 } 1957 1958 WidgetTouchEvent localEvent(aEvent); 1959 localEvent.mWidget = mPuppetWidget; 1960 1961 // Stash the guid in InputAPZContext so that when the visual-to-layout 1962 // transform is applied to the event's coordinates, we use the right transform 1963 // based on the scroll frame being targeted. 1964 // The other values don't really matter. 1965 InputAPZContext context(aGuid, aInputBlockId, aApzResponse); 1966 1967 nsTArray<TouchBehaviorFlags> allowedTouchBehaviors; 1968 if (localEvent.mMessage == eTouchStart && AsyncPanZoomEnabled()) { 1969 nsCOMPtr<Document> document = GetTopLevelDocument(); 1970 allowedTouchBehaviors = TouchActionHelper::GetAllowedTouchBehavior( 1971 mPuppetWidget, document, localEvent); 1972 if (!allowedTouchBehaviors.IsEmpty() && mApzcTreeManager) { 1973 mApzcTreeManager->SetAllowedTouchBehavior(aInputBlockId, 1974 allowedTouchBehaviors); 1975 } 1976 RefPtr<DisplayportSetListener> postLayerization = 1977 APZCCallbackHelper::SendSetTargetAPZCNotification( 1978 mPuppetWidget, document, localEvent, aGuid.mLayersId, 1979 aInputBlockId); 1980 if (postLayerization) { 1981 postLayerization->Register(); 1982 } 1983 } 1984 1985 // Dispatch event to content (potentially a long-running operation) 1986 nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent); 1987 1988 if (!AsyncPanZoomEnabled()) { 1989 // We shouldn't have any e10s platforms that have touch events enabled 1990 // without APZ. 1991 MOZ_ASSERT(false); 1992 return IPC_OK(); 1993 } 1994 1995 if (mAPZEventState) { 1996 mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId, 1997 aApzResponse, status, 1998 std::move(allowedTouchBehaviors)); 1999 } 2000 return IPC_OK(); 2001 } 2002 2003 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealTouchEvent( 2004 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid, 2005 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) { 2006 return RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse); 2007 } 2008 2009 mozilla::ipc::IPCResult BrowserChild::RecvRealTouchMoveEvent( 2010 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid, 2011 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) { 2012 if (StaticPrefs::dom_events_coalesce_touchmove()) { 2013 ++sConsecutiveTouchMoveCount; 2014 if (mCoalescedTouchMoveEventFlusher) { 2015 MOZ_ASSERT(aEvent.mMessage == eTouchMove); 2016 // NOTE: While dispatching eTouchMove or eTouchRawUpdate, 2017 // sConsecutiveTouchMoveCount may be changed by the event loop spun, 2018 // e.g., an event listener uses sync XHR or calling window.alert(). 2019 const auto PostponeDispatchingTouchMove = [&]() { 2020 return sConsecutiveTouchMoveCount > 1; 2021 }; 2022 if (mCoalescedTouchData.IsEmpty() || 2023 mCoalescedTouchData.CanCoalesce(aEvent, aGuid, aInputBlockId, 2024 aApzResponse)) { 2025 if (PostponeDispatchingTouchMove()) { 2026 WidgetTouchEvent pendingTouchMoveEvent( 2027 aEvent, WidgetTouchEvent::CloneTouches::Yes); 2028 // We don't dispatch aEvent immediately here. However, we need to 2029 // dispatch eTouchRawUpdate immediately if and only if there is a 2030 // `pointerrawupdate` event listener. Therefore, the cloned event in 2031 // the queue and it shouldn't cause eTouchRawUpdate again. 2032 pendingTouchMoveEvent.SetConvertToPointerRawUpdate(false); 2033 mCoalescedTouchData.Coalesce(pendingTouchMoveEvent, aGuid, 2034 aInputBlockId, aApzResponse); 2035 MOZ_ASSERT(PostponeDispatchingTouchMove()); 2036 mCoalescedTouchMoveEventFlusher->StartObserver(); 2037 // Let's notify the web app of `pointerrawupdate` immediately if and 2038 // only if they listen to it. 2039 HandleTouchRawUpdateEvent(pendingTouchMoveEvent, aGuid, aInputBlockId, 2040 aApzResponse); 2041 return IPC_OK(); 2042 } 2043 2044 // We'll dispatch aEvent via ProcessPendingCoalescedTouchData() below. 2045 // Therefore, the touches should cause eTouchRawUpdate event. 2046 MOZ_ASSERT(aEvent.CanConvertToPointerRawUpdate()); 2047 mCoalescedTouchData.Coalesce(aEvent, aGuid, aInputBlockId, 2048 aApzResponse); 2049 MOZ_ASSERT(!PostponeDispatchingTouchMove()); 2050 } else { 2051 UniquePtr<WidgetTouchEvent> touchMoveEvent = 2052 mCoalescedTouchData.TakeCoalescedEvent(); 2053 MOZ_ASSERT(touchMoveEvent->mMessage == eTouchMove); 2054 2055 // Before dispatching touchMoveEvent, we need to put aEvent into the 2056 // queue for keeping the event order even if an event listener spins the 2057 // event loop and we'll receive another touch event. So, aEvent may be 2058 // dispatched while we're dispatching touchMoveEvent. Therefore, we need 2059 // to make it convertible to eTouchRawUpdate. 2060 MOZ_ASSERT(aEvent.CanConvertToPointerRawUpdate()); 2061 mCoalescedTouchData.Coalesce(aEvent, aGuid, aInputBlockId, 2062 aApzResponse); 2063 MOZ_ASSERT(!PostponeDispatchingTouchMove()); 2064 2065 // touchMoveEvent was stored by mCoalescedTouchData before receiving 2066 // aEvent. Therefore, the receiver should've already dispatched 2067 // eTouchRawUpdate for dispatching `pointerrawupdate` and let web apps 2068 // know the update immediately (with sacrificing the performance). 2069 // Therefore, we don't need to dispatch eTouchRawUpdate here before 2070 // dispatching the touchMoveEvent. 2071 MOZ_ASSERT(!touchMoveEvent->CanConvertToPointerRawUpdate()); 2072 const uint32_t generation = mCoalescedTouchData.Generation(); 2073 if (!RecvRealTouchEvent(*touchMoveEvent, 2074 mCoalescedTouchData.GetScrollableLayerGuid(), 2075 mCoalescedTouchData.GetInputBlockId(), 2076 mCoalescedTouchData.GetApzResponse())) { 2077 return IPC_FAIL_NO_REASON(this); 2078 } 2079 // RecvRealTouchEvent() may have caused spinning the event loop and 2080 // changed sConsecutiveTouchMoveCount. So, we need to check it now. 2081 if (PostponeDispatchingTouchMove()) { 2082 mCoalescedTouchMoveEventFlusher->StartObserver(); 2083 if (generation == mCoalescedTouchData.Generation()) { 2084 // Let's notify the web app of `pointerrawupdate` immediately if and 2085 // only if they listen to it. Additionally, we don't want to notify 2086 // eTouchRawUpdate when ProcessPendingCoalescedTouchData() is called 2087 // later. 2088 mCoalescedTouchData.NotifyTouchRawUpdateOfHandled(aEvent); 2089 HandleTouchRawUpdateEvent(aEvent, aGuid, aInputBlockId, 2090 aApzResponse); 2091 } 2092 return IPC_OK(); 2093 } 2094 } 2095 // Flush the pending coalesced touch in order to avoid the first 2096 // touchmove be overridden by the second one, this contains aEvent. 2097 ProcessPendingCoalescedTouchData(); 2098 return IPC_OK(); 2099 } 2100 } 2101 2102 if (!RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse)) { 2103 return IPC_FAIL_NO_REASON(this); 2104 } 2105 return IPC_OK(); 2106 } 2107 2108 void BrowserChild::HandleTouchRawUpdateEvent( 2109 const WidgetTouchEvent& aPendingTouchEvent, 2110 const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId, 2111 const nsEventStatus& aApzResponse) { 2112 if (!mPointerRawUpdateWindowCount) { 2113 return; // There is no window containing pointerrawupdate event listeners 2114 } 2115 2116 WidgetTouchEvent touchRawUpdateEvent(aPendingTouchEvent, 2117 WidgetTouchEvent::CloneTouches::Yes); 2118 touchRawUpdateEvent.mMessage = eTouchRawUpdate; 2119 for (Touch* const touch : touchRawUpdateEvent.mTouches) { 2120 touch->mMessage = eTouchRawUpdate; 2121 touch->mCoalescedWidgetEvents = nullptr; 2122 touch->convertToPointer = true; 2123 // Although nobody checks `convertToPointerRawUpdate` of eTouchRawUpdate. 2124 // However, the name indicates it would cause ePointerRawUpdate or not, so, 2125 // for avoiding to make developers confused when they watch the value with 2126 // the debugger, we should set this to `true`. 2127 touch->convertToPointerRawUpdate = true; 2128 } 2129 RecvRealTouchEvent(touchRawUpdateEvent, aGuid, aInputBlockId, aApzResponse); 2130 } 2131 2132 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealTouchMoveEvent( 2133 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid, 2134 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) { 2135 return RecvRealTouchMoveEvent(aEvent, aGuid, aInputBlockId, aApzResponse); 2136 } 2137 2138 mozilla::ipc::IPCResult BrowserChild::RecvRealDragEvent( 2139 const WidgetDragEvent& aEvent, const uint32_t& aDragAction, 2140 const uint32_t& aDropEffect, nsIPrincipal* aPrincipal, 2141 nsIPolicyContainer* aPolicyContainer) { 2142 WidgetDragEvent localEvent(aEvent); 2143 localEvent.mWidget = mPuppetWidget; 2144 2145 nsCOMPtr<nsIDragSession> dragSession = GetDragSession(); 2146 DRAGSERVICE_LOGD( 2147 "[%p] %s | aEvent.mMessage: %s | aDragAction: %u | aDropEffect: %u | " 2148 "widgetRelativePt: (%d,%d) | dragSession: %p", 2149 this, __FUNCTION__, 2150 NS_ConvertUTF16toUTF8(dom::Event::GetEventName(aEvent.mMessage)).get(), 2151 aDragAction, aDropEffect, static_cast<int>(localEvent.mRefPoint.x), 2152 static_cast<int>(localEvent.mRefPoint.y), dragSession.get()); 2153 if (dragSession) { 2154 dragSession->SetDragAction(aDragAction); 2155 dragSession->SetTriggeringPrincipal(aPrincipal); 2156 dragSession->SetPolicyContainer(aPolicyContainer); 2157 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer(); 2158 if (initialDataTransfer) { 2159 initialDataTransfer->SetDropEffectInt(aDropEffect); 2160 } 2161 } 2162 2163 if (aEvent.mMessage == eDrop) { 2164 bool canDrop = true; 2165 if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) || 2166 !canDrop) { 2167 DRAGSERVICE_LOGD("[%p] %s | changed drop to dragexit", this, 2168 __FUNCTION__); 2169 localEvent.mMessage = eDragExit; 2170 } 2171 } else if (aEvent.mMessage == eDragOver) { 2172 if (dragSession) { 2173 // This will dispatch 'drag' event at the source if the 2174 // drag transaction started in this process. 2175 dragSession->FireDragEventAtSource(eDrag, aEvent.mModifiers); 2176 } 2177 } 2178 2179 DispatchWidgetEventViaAPZ(localEvent); 2180 return IPC_OK(); 2181 } 2182 2183 already_AddRefed<DataTransfer> BrowserChild::ConvertToDataTransfer( 2184 nsIPrincipal* aPrincipal, nsTArray<IPCTransferableData>&& aTransferables, 2185 EventMessage aMessage) { 2186 // The extension process should grant access to a protected DataTransfer if 2187 // the principal permits it (and dom.events.datatransfer.protected.enabled is 2188 // false). Otherwise, protected DataTransfer access should only be given to 2189 // the system. 2190 if (!aPrincipal || Manager()->GetRemoteType() != EXTENSION_REMOTE_TYPE) { 2191 aPrincipal = nsContentUtils::GetSystemPrincipal(); 2192 } 2193 2194 // Check if we are receiving any file objects. If we are we will want 2195 // to hide any of the other objects coming in from content. 2196 bool hasFiles = false; 2197 for (uint32_t i = 0; i < aTransferables.Length() && !hasFiles; ++i) { 2198 auto& items = aTransferables[i].items(); 2199 for (uint32_t j = 0; j < items.Length() && !hasFiles; ++j) { 2200 if (items[j].data().type() == 2201 IPCTransferableDataType::TIPCTransferableDataBlob) { 2202 hasFiles = true; 2203 } 2204 } 2205 } 2206 // Add the entries from the IPC to the new DataTransfer 2207 RefPtr<DataTransfer> dataTransfer = 2208 new DataTransfer(nullptr, aMessage, false, Nothing()); 2209 for (uint32_t i = 0; i < aTransferables.Length(); ++i) { 2210 auto& items = aTransferables[i].items(); 2211 for (uint32_t j = 0; j < items.Length(); ++j) { 2212 const IPCTransferableDataItem& item = items[j]; 2213 RefPtr<nsVariantCC> variant = new nsVariantCC(); 2214 nsresult rv = 2215 nsContentUtils::IPCTransferableDataItemToVariant(item, variant); 2216 if (NS_FAILED(rv)) { 2217 continue; 2218 } 2219 2220 // We should hide this data from content if we have a file, and we 2221 // aren't a file. 2222 bool hidden = 2223 hasFiles && item.data().type() != 2224 IPCTransferableDataType::TIPCTransferableDataBlob; 2225 dataTransfer->SetDataWithPrincipalFromOtherProcess( 2226 NS_ConvertUTF8toUTF16(item.flavor()), variant, i, aPrincipal, hidden); 2227 } 2228 } 2229 return dataTransfer.forget(); 2230 } 2231 2232 mozilla::ipc::IPCResult BrowserChild::RecvInvokeChildDragSession( 2233 const MaybeDiscarded<WindowContext>& aSourceWindowContext, 2234 const MaybeDiscarded<WindowContext>& aSourceTopWindowContext, 2235 nsIPrincipal* aPrincipal, nsTArray<IPCTransferableData>&& aTransferables, 2236 const uint32_t& aAction) { 2237 if (nsCOMPtr<nsIDragService> dragService = 2238 do_GetService("@mozilla.org/widget/dragservice;1")) { 2239 nsIWidget* widget = WebWidget(); 2240 dragService->StartDragSession(widget); 2241 if (RefPtr<nsIDragSession> session = GetDragSession()) { 2242 session->SetSourceWindowContext(aSourceWindowContext.GetMaybeDiscarded()); 2243 session->SetSourceTopWindowContext( 2244 aSourceTopWindowContext.GetMaybeDiscarded()); 2245 session->SetDragAction(aAction); 2246 RefPtr<DataTransfer> dataTransfer = ConvertToDataTransfer( 2247 aPrincipal, std::move(aTransferables), eDragStart); 2248 session->SetDataTransfer(dataTransfer); 2249 DRAGSERVICE_LOGD("[%p] %s | Successfully started dragSession: %p", this, 2250 __FUNCTION__, session.get()); 2251 } else { 2252 DRAGSERVICE_LOGE("[%p] %s | Failed to start dragSession", this, 2253 __FUNCTION__); 2254 } 2255 } 2256 return IPC_OK(); 2257 } 2258 2259 mozilla::ipc::IPCResult BrowserChild::RecvUpdateDragSession( 2260 nsIPrincipal* aPrincipal, nsTArray<IPCTransferableData>&& aTransferables, 2261 EventMessage aEventMessage) { 2262 if (RefPtr<nsIDragSession> session = GetDragSession()) { 2263 nsCOMPtr<DataTransfer> dataTransfer = ConvertToDataTransfer( 2264 aPrincipal, std::move(aTransferables), aEventMessage); 2265 session->SetDataTransfer(dataTransfer); 2266 DRAGSERVICE_LOGD( 2267 "[%p] %s | session: %p | aEventMessage: %s | Updated dragSession " 2268 "dataTransfer", 2269 this, __FUNCTION__, session.get(), 2270 NS_ConvertUTF16toUTF8(dom::Event::GetEventName(aEventMessage)).get()); 2271 } 2272 return IPC_OK(); 2273 } 2274 2275 mozilla::ipc::IPCResult BrowserChild::RecvEndDragSession( 2276 const bool& aDoneDrag, const bool& aUserCancelled, 2277 const LayoutDeviceIntPoint& aDragEndPoint, const uint32_t& aKeyModifiers, 2278 const uint32_t& aDropEffect) { 2279 RefPtr<nsIDragSession> dragSession = GetDragSession(); 2280 if (dragSession) { 2281 DRAGSERVICE_LOGD( 2282 "[%p] %s | dragSession: %p | aDoneDrag: %s | aUserCancelled: %s | " 2283 "aDragEndPoint: (%d, %d) | aKeyModifiers: %u | aDropEffect: %u", 2284 this, __FUNCTION__, dragSession.get(), TrueOrFalse(aDoneDrag), 2285 TrueOrFalse(aUserCancelled), static_cast<int>(aDragEndPoint.x), 2286 static_cast<int>(aDragEndPoint.y), aKeyModifiers, aDropEffect); 2287 2288 if (aUserCancelled) { 2289 dragSession->UserCancelled(); 2290 } 2291 2292 RefPtr<DataTransfer> dataTransfer = dragSession->GetDataTransfer(); 2293 if (dataTransfer) { 2294 dataTransfer->SetDropEffectInt(aDropEffect); 2295 } 2296 dragSession->SetDragEndPoint(aDragEndPoint.x, aDragEndPoint.y); 2297 dragSession->EndDragSession(aDoneDrag, aKeyModifiers); 2298 } 2299 return IPC_OK(); 2300 } 2301 2302 mozilla::ipc::IPCResult BrowserChild::RecvStoreDropTargetAndDelayEndDragSession( 2303 const LayoutDeviceIntPoint& aPt, uint32_t aDropEffect, uint32_t aDragAction, 2304 nsIPrincipal* aPrincipal, nsIPolicyContainer* aPolicyContainer) { 2305 // cf. RecvRealDragEvent 2306 nsCOMPtr<nsIDragSession> dragSession = GetDragSession(); 2307 MOZ_ASSERT(dragSession); 2308 DRAGSERVICE_LOGD( 2309 "[%p] %s | dragSession: %p aPt: (%d, %d) | aDropEffect: %u | " 2310 "aDragAction: %u", 2311 this, __FUNCTION__, dragSession.get(), static_cast<int>(aPt.x), 2312 static_cast<int>(aPt.y), aDropEffect, aDragAction); 2313 dragSession->SetDragAction(aDragAction); 2314 dragSession->SetTriggeringPrincipal(aPrincipal); 2315 dragSession->SetPolicyContainer(aPolicyContainer); 2316 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer(); 2317 if (initialDataTransfer) { 2318 initialDataTransfer->SetDropEffectInt(aDropEffect); 2319 } 2320 2321 bool canDrop = true; 2322 if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) || 2323 !canDrop) { 2324 // Don't record the target or delay EDS calls. 2325 return IPC_OK(); 2326 } 2327 2328 auto parentToChildTf = GetChildToParentConversionMatrix().MaybeInverse(); 2329 NS_ENSURE_TRUE(parentToChildTf, IPC_OK()); 2330 LayoutDevicePoint floatPt(aPt); 2331 LayoutDevicePoint floatTf = parentToChildTf->TransformPoint(floatPt); 2332 WidgetQueryContentEvent queryEvent(true, eQueryDropTargetHittest, 2333 mPuppetWidget); 2334 queryEvent.mRefPoint = RoundedToInt(floatTf); 2335 DispatchWidgetEventViaAPZ(queryEvent); 2336 if (queryEvent.mReply && queryEvent.mReply->mDropElement) { 2337 mDelayedDropPoint = queryEvent.mRefPoint; 2338 dragSession->StoreDropTargetAndDelayEndDragSession( 2339 queryEvent.mReply->mDropElement, queryEvent.mReply->mDropFrame); 2340 } else { 2341 MOZ_ASSERT(false, "Didn't get reply from eQueryDropTargetHittest event!"); 2342 } 2343 return IPC_OK(); 2344 } 2345 2346 mozilla::ipc::IPCResult 2347 BrowserChild::RecvDispatchToDropTargetAndResumeEndDragSession( 2348 bool aShouldDrop, nsTHashSet<nsString>&& aAllowedFilesPaths) { 2349 DRAGSERVICE_LOGD("[%p] %s | aShouldDrop: %s", this, __FUNCTION__, 2350 TrueOrFalse(aShouldDrop)); 2351 nsCOMPtr<nsIDragSession> dragSession = GetDragSession(); 2352 MOZ_ASSERT(dragSession); 2353 RefPtr<nsIWidget> widget = mPuppetWidget; 2354 nsTHashSet<nsString> allowedPaths = 2355 aShouldDrop ? std::move(aAllowedFilesPaths) : nsTHashSet<nsString>(); 2356 dragSession->DispatchToDropTargetAndResumeEndDragSession( 2357 widget, mDelayedDropPoint, aShouldDrop, allowedPaths); 2358 mDelayedDropPoint = {}; 2359 return IPC_OK(); 2360 } 2361 2362 void BrowserChild::RequestEditCommands(NativeKeyBindingsType aType, 2363 const WidgetKeyboardEvent& aEvent, 2364 nsTArray<CommandInt>& aCommands) { 2365 MOZ_ASSERT(aCommands.IsEmpty()); 2366 2367 if (NS_WARN_IF(aEvent.IsEditCommandsInitialized(aType))) { 2368 aCommands = aEvent.EditCommandsConstRef(aType).Clone(); 2369 return; 2370 } 2371 2372 switch (aType) { 2373 case NativeKeyBindingsType::SingleLineEditor: 2374 case NativeKeyBindingsType::MultiLineEditor: 2375 case NativeKeyBindingsType::RichTextEditor: 2376 break; 2377 default: 2378 MOZ_ASSERT_UNREACHABLE("Invalid native key bindings type"); 2379 } 2380 2381 // Don't send aEvent to the parent process directly because it'll be marked 2382 // as posted to remote process. 2383 WidgetKeyboardEvent localEvent(aEvent); 2384 SendRequestNativeKeyBindings(static_cast<uint32_t>(aType), localEvent, 2385 &aCommands); 2386 } 2387 2388 mozilla::ipc::IPCResult BrowserChild::RecvSynthesizedEventResponse( 2389 const uint64_t& aCallbackId) { 2390 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event")); 2391 mozilla::widget::AutoSynthesizedEventCallbackNotifier::NotifySavedCallback( 2392 aCallbackId); 2393 return IPC_OK(); 2394 } 2395 2396 mozilla::ipc::IPCResult BrowserChild::RecvUpdateSHistory() { 2397 if (mSessionStoreChild) { 2398 mSessionStoreChild->UpdateSHistoryChanges(); 2399 } 2400 return IPC_OK(); 2401 } 2402 2403 // In case handling repeated keys takes much time, we skip firing new ones. 2404 bool BrowserChild::SkipRepeatedKeyEvent(const WidgetKeyboardEvent& aEvent) { 2405 if (mRepeatedKeyEventTime.IsNull() || !aEvent.CanSkipInRemoteProcess() || 2406 (aEvent.mMessage != eKeyDown && aEvent.mMessage != eKeyPress)) { 2407 mRepeatedKeyEventTime = TimeStamp(); 2408 mSkipKeyPress = false; 2409 return false; 2410 } 2411 2412 if ((aEvent.mMessage == eKeyDown && 2413 (mRepeatedKeyEventTime > aEvent.mTimeStamp)) || 2414 (mSkipKeyPress && (aEvent.mMessage == eKeyPress))) { 2415 // If we skip a keydown event, also the following keypress events should be 2416 // skipped. 2417 mSkipKeyPress |= aEvent.mMessage == eKeyDown; 2418 return true; 2419 } 2420 2421 if (aEvent.mMessage == eKeyDown) { 2422 // If keydown wasn't skipped, nor should the possible following keypress. 2423 mRepeatedKeyEventTime = TimeStamp(); 2424 mSkipKeyPress = false; 2425 } 2426 return false; 2427 } 2428 2429 void BrowserChild::UpdateRepeatedKeyEventEndTime( 2430 const WidgetKeyboardEvent& aEvent) { 2431 if (aEvent.mIsRepeat && 2432 (aEvent.mMessage == eKeyDown || aEvent.mMessage == eKeyPress)) { 2433 mRepeatedKeyEventTime = TimeStamp::Now(); 2434 } 2435 } 2436 2437 mozilla::ipc::IPCResult BrowserChild::RecvRealKeyEvent( 2438 const WidgetKeyboardEvent& aEvent, const nsID& aUUID) { 2439 MOZ_ASSERT_IF(aEvent.mMessage == eKeyPress, 2440 aEvent.AreAllEditCommandsInitialized()); 2441 2442 // If content code called preventDefault() on a keydown event, then we don't 2443 // want to process any following keypress events which is caused by the 2444 // preceding keydown (i.e., default action of the preceding keydown). 2445 // In other words, if the keypress is not a default action of the preceding 2446 // keydown, we should not stop dispatching keypress event even if the 2447 // immediate preceding keydown was consumed. 2448 const bool isPrecedingKeyDownEventConsumed = 2449 aEvent.mMessage == eKeyPress && mPreviousConsumedKeyDownCode.isSome() && 2450 mPreviousConsumedKeyDownCode.value() == aEvent.mCodeNameIndex; 2451 2452 WidgetKeyboardEvent localEvent(aEvent); 2453 localEvent.mWidget = mPuppetWidget; 2454 localEvent.mUniqueId = aEvent.mUniqueId; 2455 2456 if (!SkipRepeatedKeyEvent(aEvent) && !isPrecedingKeyDownEventConsumed) { 2457 nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent); 2458 2459 // Update the end time of the possible repeated event so that we can skip 2460 // some incoming events in case event handling took long time. 2461 UpdateRepeatedKeyEventEndTime(localEvent); 2462 2463 if (aEvent.mMessage == eKeyDown) { 2464 // If eKeyDown is consumed, we should stop dispatching the following 2465 // eKeyPress events since the events are default action of eKeyDown. 2466 // FIXME: We should synthesize eKeyPress in this process (bug 1181501). 2467 if (status == nsEventStatus_eConsumeNoDefault) { 2468 MOZ_ASSERT_IF(!aEvent.mFlags.mIsSynthesizedForTests, 2469 aEvent.mCodeNameIndex != CODE_NAME_INDEX_USE_STRING); 2470 // If mPreviousConsumedKeyDownCode is not Nothing, 2 or more keys may be 2471 // pressed at same time and their eKeyDown are consumed. However, we 2472 // forget the previous eKeyDown event result here and that might cause 2473 // dispatching eKeyPress events caused by the previous eKeyDown in 2474 // theory. However, this should not occur because eKeyPress should be 2475 // fired before another eKeyDown, although it's depend on how the native 2476 // keyboard event handler is implemented. 2477 mPreviousConsumedKeyDownCode = Some(aEvent.mCodeNameIndex); 2478 } 2479 // If eKeyDown is not consumed but we know preceding eKeyDown is consumed, 2480 // we need to forget it since we should not stop dispatching following 2481 // eKeyPress events which are default action of current eKeyDown. 2482 else if (mPreviousConsumedKeyDownCode.isSome() && 2483 aEvent.mCodeNameIndex == mPreviousConsumedKeyDownCode.value()) { 2484 mPreviousConsumedKeyDownCode.reset(); 2485 } 2486 } 2487 // eKeyPress is a default action of eKeyDown. Therefore, eKeyPress is fired 2488 // between eKeyDown and eKeyUp. So, received an eKeyUp for eKeyDown which 2489 // was consumed means that following eKeyPress events should be dispatched. 2490 // Therefore, we need to forget the fact that the preceding eKeyDown was 2491 // consumed right now. 2492 // NOTE: On Windows, eKeyPress may be fired without preceding eKeyDown if 2493 // IME or utility app sends WM_CHAR message. So, if we don't forget it, 2494 // we'd consume unrelated eKeyPress events. 2495 else if (aEvent.mMessage == eKeyUp && 2496 mPreviousConsumedKeyDownCode.isSome() && 2497 aEvent.mCodeNameIndex == mPreviousConsumedKeyDownCode.value()) { 2498 mPreviousConsumedKeyDownCode.reset(); 2499 } 2500 2501 if (localEvent.mFlags.mIsSuppressedOrDelayed) { 2502 localEvent.PreventDefault(); 2503 } 2504 2505 // If the event's default isn't prevented but the status is no default, 2506 // That means that the event was consumed by EventStateManager or something 2507 // which is not a usual event handler. In such case, prevent its default 2508 // as a default handler. For example, when an eKeyPress event matches 2509 // with a content accesskey, and it's executed, preventDefault() of the 2510 // event won't be called but the status is set to "no default". Then, 2511 // the event shouldn't be handled by nsMenuBarListener in the main process. 2512 if (!localEvent.DefaultPrevented() && 2513 status == nsEventStatus_eConsumeNoDefault) { 2514 localEvent.PreventDefault(); 2515 } 2516 2517 MOZ_DIAGNOSTIC_ASSERT(!localEvent.PropagationStopped()); 2518 } 2519 // The keyboard event which we ignore should not be handled in the main 2520 // process for shortcut key handling. For notifying if we skipped it, we can 2521 // use "stop propagation" flag here because it must be cleared by 2522 // `EventTargetChainItem` if we've dispatched it. 2523 else { 2524 localEvent.StopPropagation(); 2525 } 2526 2527 // If we don't need to send a rely for the given keyboard event, we do nothing 2528 // anymore here. 2529 if (!aEvent.WantReplyFromContentProcess()) { 2530 return IPC_OK(); 2531 } 2532 2533 // This is an ugly hack, mNoRemoteProcessDispatch is set to true when the 2534 // event's PreventDefault() or StopScrollProcessForwarding() is called. 2535 // And then, it'll be checked by ParamTraits<mozilla::WidgetEvent>::Write() 2536 // whether the event is being sent to remote process unexpectedly. 2537 // However, unfortunately, it cannot check the destination. Therefore, 2538 // we need to clear the flag explicitly here because ParamTraits should 2539 // keep checking the flag for avoiding regression. 2540 localEvent.mFlags.mNoRemoteProcessDispatch = false; 2541 SendReplyKeyEvent(localEvent, aUUID); 2542 2543 return IPC_OK(); 2544 } 2545 2546 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealKeyEvent( 2547 const WidgetKeyboardEvent& aEvent, const nsID& aUUID) { 2548 return RecvRealKeyEvent(aEvent, aUUID); 2549 } 2550 2551 mozilla::ipc::IPCResult BrowserChild::RecvCompositionEvent( 2552 const WidgetCompositionEvent& aEvent) { 2553 WidgetCompositionEvent localEvent(aEvent); 2554 localEvent.mWidget = mPuppetWidget; 2555 DispatchWidgetEventViaAPZ(localEvent); 2556 (void)SendOnEventNeedingAckHandled(aEvent.mMessage, 2557 localEvent.mCompositionId); 2558 return IPC_OK(); 2559 } 2560 2561 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityCompositionEvent( 2562 const WidgetCompositionEvent& aEvent) { 2563 return RecvCompositionEvent(aEvent); 2564 } 2565 2566 mozilla::ipc::IPCResult BrowserChild::RecvSelectionEvent( 2567 const WidgetSelectionEvent& aEvent) { 2568 WidgetSelectionEvent localEvent(aEvent); 2569 localEvent.mWidget = mPuppetWidget; 2570 DispatchWidgetEventViaAPZ(localEvent); 2571 (void)SendOnEventNeedingAckHandled(aEvent.mMessage, 0u); 2572 return IPC_OK(); 2573 } 2574 2575 mozilla::ipc::IPCResult BrowserChild::RecvNormalPrioritySelectionEvent( 2576 const WidgetSelectionEvent& aEvent) { 2577 return RecvSelectionEvent(aEvent); 2578 } 2579 2580 mozilla::ipc::IPCResult BrowserChild::RecvSimpleContentCommandEvent( 2581 const EventMessage& aMessage) { 2582 WidgetContentCommandEvent localEvent(true, aMessage, mPuppetWidget); 2583 DispatchWidgetEventViaAPZ(localEvent); 2584 (void)SendOnEventNeedingAckHandled(aMessage, 0u); 2585 return IPC_OK(); 2586 } 2587 2588 mozilla::ipc::IPCResult 2589 BrowserChild::RecvNormalPrioritySimpleContentCommandEvent( 2590 const EventMessage& aMessage) { 2591 return RecvSimpleContentCommandEvent(aMessage); 2592 } 2593 2594 mozilla::ipc::IPCResult BrowserChild::RecvInsertText( 2595 const nsAString& aStringToInsert) { 2596 // Use normal event path to reach focused document. 2597 WidgetContentCommandEvent localEvent(true, eContentCommandInsertText, 2598 mPuppetWidget); 2599 localEvent.mString = Some(nsString(aStringToInsert)); 2600 DispatchWidgetEventViaAPZ(localEvent); 2601 (void)SendOnEventNeedingAckHandled(eContentCommandInsertText, 0u); 2602 return IPC_OK(); 2603 } 2604 2605 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityInsertText( 2606 const nsAString& aStringToInsert) { 2607 return RecvInsertText(aStringToInsert); 2608 } 2609 2610 mozilla::ipc::IPCResult BrowserChild::RecvReplaceText( 2611 const nsString& aReplaceSrcString, const nsString& aStringToInsert, 2612 uint32_t aOffset, bool aPreventSetSelection) { 2613 // Use normal event path to reach focused document. 2614 WidgetContentCommandEvent localEvent(true, eContentCommandReplaceText, 2615 mPuppetWidget); 2616 localEvent.mString = Some(aStringToInsert); 2617 localEvent.mSelection.mReplaceSrcString = aReplaceSrcString; 2618 localEvent.mSelection.mOffset = aOffset; 2619 localEvent.mSelection.mPreventSetSelection = aPreventSetSelection; 2620 DispatchWidgetEventViaAPZ(localEvent); 2621 (void)SendOnEventNeedingAckHandled(eContentCommandReplaceText, 0u); 2622 return IPC_OK(); 2623 } 2624 2625 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityReplaceText( 2626 const nsString& aReplaceSrcString, const nsString& aStringToInsert, 2627 uint32_t aOffset, bool aPreventSetSelection) { 2628 return RecvReplaceText(aReplaceSrcString, aStringToInsert, aOffset, 2629 aPreventSetSelection); 2630 } 2631 2632 mozilla::ipc::IPCResult BrowserChild::RecvPasteTransferable( 2633 const IPCTransferable& aTransferable) { 2634 nsresult rv; 2635 nsCOMPtr<nsITransferable> trans = 2636 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv); 2637 NS_ENSURE_SUCCESS(rv, IPC_OK()); 2638 trans->Init(nullptr); 2639 2640 rv = nsContentUtils::IPCTransferableToTransferable( 2641 aTransferable, true /* aAddDataFlavor */, trans, 2642 false /* aFilterUnknownFlavors */); 2643 NS_ENSURE_SUCCESS(rv, IPC_OK()); 2644 2645 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation()); 2646 if (NS_WARN_IF(!ourDocShell)) { 2647 return IPC_OK(); 2648 } 2649 2650 RefPtr<nsCommandParams> params = new nsCommandParams(); 2651 rv = params->SetISupports("transferable", trans); 2652 NS_ENSURE_SUCCESS(rv, IPC_OK()); 2653 2654 ourDocShell->DoCommandWithParams("cmd_pasteTransferable", params); 2655 return IPC_OK(); 2656 } 2657 2658 #ifdef ACCESSIBILITY 2659 a11y::PDocAccessibleChild* BrowserChild::AllocPDocAccessibleChild( 2660 PDocAccessibleChild*, const uint64_t&, 2661 const MaybeDiscardedBrowsingContext&) { 2662 MOZ_ASSERT(false, "should never call this!"); 2663 return nullptr; 2664 } 2665 2666 bool BrowserChild::DeallocPDocAccessibleChild( 2667 a11y::PDocAccessibleChild* aChild) { 2668 delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild); 2669 return true; 2670 } 2671 #endif 2672 2673 RefPtr<VsyncMainChild> BrowserChild::GetVsyncChild() { 2674 // Initializing VsyncMainChild here turns on per-BrowserChild Vsync for a 2675 // given platform. Note: this only makes sense if nsWindow returns a 2676 // window-specific VsyncSource. 2677 #if defined(MOZ_WAYLAND) 2678 if (IsWaylandEnabled()) { 2679 if (auto* actor = static_cast<VsyncMainChild*>( 2680 LoneManagedOrNullAsserts(ManagedPVsyncChild()))) { 2681 return actor; 2682 } 2683 auto actor = MakeRefPtr<VsyncMainChild>(); 2684 if (!SendPVsyncConstructor(actor)) { 2685 return nullptr; 2686 } 2687 return actor; 2688 } 2689 #endif 2690 return nullptr; 2691 } 2692 2693 mozilla::ipc::IPCResult BrowserChild::RecvLoadRemoteScript( 2694 const nsAString& aURL, const bool& aRunInGlobalScope) { 2695 if (!InitBrowserChildMessageManager()) 2696 // This can happen if we're half-destroyed. It's not a fatal 2697 // error. 2698 return IPC_OK(); 2699 2700 JS::Rooted<JSObject*> mm(RootingCx(), 2701 mBrowserChildMessageManager->GetOrCreateWrapper()); 2702 if (!mm) { 2703 // This can happen if we're half-destroyed. It's not a fatal error. 2704 return IPC_OK(); 2705 } 2706 2707 LoadScriptInternal(mm, aURL, !aRunInGlobalScope); 2708 return IPC_OK(); 2709 } 2710 2711 mozilla::ipc::IPCResult BrowserChild::RecvAsyncMessage( 2712 const nsAString& aMessage, const ClonedMessageData& aData) { 2713 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserChild::RecvAsyncMessage", 2714 OTHER, aMessage); 2715 MMPrinter::Print("BrowserChild::RecvAsyncMessage", aMessage, aData); 2716 2717 if (!mBrowserChildMessageManager) { 2718 return IPC_OK(); 2719 } 2720 2721 RefPtr<nsFrameMessageManager> mm = 2722 mBrowserChildMessageManager->GetMessageManager(); 2723 2724 // We should have a message manager if the global is alive, but it 2725 // seems sometimes we don't. Assert in aurora/nightly, but don't 2726 // crash in release builds. 2727 MOZ_DIAGNOSTIC_ASSERT(mm); 2728 if (!mm) { 2729 return IPC_OK(); 2730 } 2731 2732 JS::Rooted<JSObject*> kungFuDeathGrip( 2733 dom::RootingCx(), mBrowserChildMessageManager->GetWrapper()); 2734 StructuredCloneData data; 2735 UnpackClonedMessageData(aData, data); 2736 mm->ReceiveMessage(static_cast<EventTarget*>(mBrowserChildMessageManager), 2737 nullptr, aMessage, false, &data, nullptr, IgnoreErrors()); 2738 return IPC_OK(); 2739 } 2740 2741 mozilla::ipc::IPCResult BrowserChild::RecvSwappedWithOtherRemoteLoader( 2742 const IPCTabContext& aContext) { 2743 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation()); 2744 if (NS_WARN_IF(!ourDocShell)) { 2745 return IPC_OK(); 2746 } 2747 2748 nsCOMPtr<nsPIDOMWindowOuter> ourWindow = ourDocShell->GetWindow(); 2749 if (NS_WARN_IF(!ourWindow)) { 2750 return IPC_OK(); 2751 } 2752 2753 RefPtr<nsDocShell> docShell = static_cast<nsDocShell*>(ourDocShell.get()); 2754 2755 nsCOMPtr<EventTarget> ourEventTarget = nsGlobalWindowOuter::Cast(ourWindow); 2756 2757 docShell->SetInFrameSwap(true); 2758 2759 nsContentUtils::FirePageShowEventForFrameLoaderSwap( 2760 ourDocShell, ourEventTarget, false, true); 2761 nsContentUtils::FirePageHideEventForFrameLoaderSwap(ourDocShell, 2762 ourEventTarget, true); 2763 2764 // Owner content type may have changed, so store the possibly updated context 2765 // and notify others. 2766 MaybeInvalidTabContext maybeContext(aContext); 2767 if (!maybeContext.IsValid()) { 2768 NS_ERROR(nsPrintfCString("Received an invalid TabContext from " 2769 "the parent process. (%s)", 2770 maybeContext.GetInvalidReason()) 2771 .get()); 2772 MOZ_CRASH("Invalid TabContext received from the parent process."); 2773 } 2774 2775 if (!UpdateTabContextAfterSwap(maybeContext.GetTabContext())) { 2776 MOZ_CRASH("Update to TabContext after swap was denied."); 2777 } 2778 2779 // Ignore previous value of mTriedBrowserInit since owner content has changed. 2780 mTriedBrowserInit = true; 2781 2782 nsContentUtils::FirePageShowEventForFrameLoaderSwap( 2783 ourDocShell, ourEventTarget, true, true); 2784 2785 docShell->SetInFrameSwap(false); 2786 2787 // This is needed to get visibility state right in cases when we swapped a 2788 // visible tab (foreground in visible window) with a non-visible tab. 2789 if (RefPtr<Document> doc = docShell->GetDocument()) { 2790 doc->UpdateVisibilityState(); 2791 } 2792 2793 return IPC_OK(); 2794 } 2795 2796 mozilla::ipc::IPCResult BrowserChild::RecvHandleAccessKey( 2797 const WidgetKeyboardEvent& aEvent, nsTArray<uint32_t>&& aCharCodes) { 2798 nsCOMPtr<Document> document(GetTopLevelDocument()); 2799 RefPtr<nsPresContext> pc = document->GetPresContext(); 2800 if (pc) { 2801 if (!pc->EventStateManager()->HandleAccessKey( 2802 &(const_cast<WidgetKeyboardEvent&>(aEvent)), pc, aCharCodes)) { 2803 // If no accesskey was found, inform the parent so that accesskeys on 2804 // menus can be handled. 2805 WidgetKeyboardEvent localEvent(aEvent); 2806 localEvent.mWidget = mPuppetWidget; 2807 SendAccessKeyNotHandled(localEvent); 2808 } 2809 } 2810 2811 return IPC_OK(); 2812 } 2813 2814 mozilla::ipc::IPCResult BrowserChild::RecvPrintPreview( 2815 const PrintData& aPrintData, const MaybeDiscardedBrowsingContext& aSourceBC, 2816 PrintPreviewResolver&& aCallback) { 2817 #ifdef NS_PRINTING 2818 // If we didn't succeed in passing off ownership of aCallback, then something 2819 // went wrong. 2820 auto sendCallbackError = MakeScopeExit([&] { 2821 if (aCallback) { 2822 // signal error 2823 aCallback(PrintPreviewResultInfo(0, 0, false, false, false, {}, {}, {})); 2824 } 2825 }); 2826 2827 if (NS_WARN_IF(aSourceBC.IsDiscarded())) { 2828 return IPC_OK(); 2829 } 2830 2831 RefPtr<nsGlobalWindowOuter> sourceWindow; 2832 if (!aSourceBC.IsNull()) { 2833 sourceWindow = nsGlobalWindowOuter::Cast(aSourceBC.get()->GetDOMWindow()); 2834 if (NS_WARN_IF(!sourceWindow)) { 2835 return IPC_OK(); 2836 } 2837 } else { 2838 nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_GetInterface(WebNavigation()); 2839 if (NS_WARN_IF(!ourWindow)) { 2840 return IPC_OK(); 2841 } 2842 sourceWindow = nsGlobalWindowOuter::Cast(ourWindow); 2843 } 2844 2845 RefPtr<nsIPrintSettings> printSettings; 2846 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc = 2847 do_GetService("@mozilla.org/gfx/printsettings-service;1"); 2848 if (NS_WARN_IF(!printSettingsSvc)) { 2849 return IPC_OK(); 2850 } 2851 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings)); 2852 if (NS_WARN_IF(!printSettings)) { 2853 return IPC_OK(); 2854 } 2855 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings); 2856 2857 nsCOMPtr<nsIDocShell> docShellToCloneInto; 2858 if (!aSourceBC.IsNull()) { 2859 docShellToCloneInto = do_GetInterface(WebNavigation()); 2860 if (NS_WARN_IF(!docShellToCloneInto)) { 2861 return IPC_OK(); 2862 } 2863 } 2864 2865 sourceWindow->Print(printSettings, 2866 /* aRemotePrintJob = */ nullptr, 2867 /* aListener = */ nullptr, docShellToCloneInto, 2868 nsGlobalWindowOuter::IsPreview::Yes, 2869 nsGlobalWindowOuter::IsForWindowDotPrint::No, 2870 std::move(aCallback), nullptr, IgnoreErrors()); 2871 #endif 2872 return IPC_OK(); 2873 } 2874 2875 mozilla::ipc::IPCResult BrowserChild::RecvExitPrintPreview() { 2876 #ifdef NS_PRINTING 2877 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint = 2878 do_GetInterface(ToSupports(WebNavigation())); 2879 if (NS_WARN_IF(!webBrowserPrint)) { 2880 return IPC_OK(); 2881 } 2882 webBrowserPrint->ExitPrintPreview(); 2883 #endif 2884 return IPC_OK(); 2885 } 2886 2887 mozilla::ipc::IPCResult BrowserChild::CommonPrint( 2888 const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData, 2889 RefPtr<BrowsingContext>* aCachedBrowsingContext) { 2890 #ifdef NS_PRINTING 2891 if (NS_WARN_IF(aBc.IsNullOrDiscarded())) { 2892 return IPC_OK(); 2893 } 2894 RefPtr<nsGlobalWindowOuter> outerWindow = 2895 nsGlobalWindowOuter::Cast(aBc.get()->GetDOMWindow()); 2896 if (NS_WARN_IF(!outerWindow)) { 2897 return IPC_OK(); 2898 } 2899 2900 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc = 2901 do_GetService("@mozilla.org/gfx/printsettings-service;1"); 2902 if (NS_WARN_IF(!printSettingsSvc)) { 2903 return IPC_OK(); 2904 } 2905 2906 nsCOMPtr<nsIPrintSettings> printSettings; 2907 nsresult rv = 2908 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings)); 2909 if (NS_WARN_IF(NS_FAILED(rv))) { 2910 return IPC_OK(); 2911 } 2912 2913 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings); 2914 { 2915 IgnoredErrorResult rv; 2916 RefPtr printJob = static_cast<RemotePrintJobChild*>( 2917 aPrintData.remotePrintJob().AsChild()); 2918 outerWindow->Print( 2919 printSettings, printJob, 2920 /* aListener = */ nullptr, 2921 /* aWindowToCloneInto = */ nullptr, nsGlobalWindowOuter::IsPreview::No, 2922 nsGlobalWindowOuter::IsForWindowDotPrint::No, 2923 /* aPrintPreviewCallback = */ nullptr, aCachedBrowsingContext, rv); 2924 if (NS_WARN_IF(rv.Failed())) { 2925 return IPC_OK(); 2926 } 2927 } 2928 #endif 2929 return IPC_OK(); 2930 } 2931 2932 mozilla::ipc::IPCResult BrowserChild::RecvPrint( 2933 const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData, 2934 bool aReturnStaticClone, PrintResolver&& aResolve) { 2935 #ifdef NS_PRINTING 2936 RefPtr<BrowsingContext> browsingContext; 2937 auto result = CommonPrint(aBc, aPrintData, 2938 aReturnStaticClone ? &browsingContext : nullptr); 2939 aResolve(browsingContext); 2940 return result; 2941 #else 2942 aResolve(nullptr); 2943 return IPC_OK(); 2944 #endif 2945 } 2946 2947 mozilla::ipc::IPCResult BrowserChild::RecvPrintClonedPage( 2948 const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData, 2949 const MaybeDiscardedBrowsingContext& aClonedBc) { 2950 #ifdef NS_PRINTING 2951 if (aClonedBc.IsNullOrDiscarded()) { 2952 return IPC_OK(); 2953 } 2954 RefPtr<BrowsingContext> clonedBc = aClonedBc.get(); 2955 return CommonPrint(aBc, aPrintData, &clonedBc); 2956 #else 2957 return IPC_OK(); 2958 #endif 2959 } 2960 2961 mozilla::ipc::IPCResult BrowserChild::RecvDestroyPrintClone( 2962 const MaybeDiscardedBrowsingContext& aCachedPage) { 2963 #ifdef NS_PRINTING 2964 if (aCachedPage) { 2965 RefPtr<nsPIDOMWindowOuter> window = aCachedPage->GetDOMWindow(); 2966 if (NS_WARN_IF(!window)) { 2967 return IPC_OK(); 2968 } 2969 window->Close(); 2970 } 2971 #endif 2972 return IPC_OK(); 2973 } 2974 2975 mozilla::ipc::IPCResult BrowserChild::RecvUpdateNativeWindowHandle( 2976 const uintptr_t& aNewHandle) { 2977 #if defined(XP_WIN) && defined(ACCESSIBILITY) 2978 mNativeWindowHandle = aNewHandle; 2979 return IPC_OK(); 2980 #else 2981 return IPC_FAIL_NO_REASON(this); 2982 #endif 2983 } 2984 2985 mozilla::ipc::IPCResult BrowserChild::RecvDestroy() { 2986 MOZ_ASSERT(!mDestroyed); 2987 mDestroyed = true; 2988 2989 nsTArray<PContentPermissionRequestChild*> childArray = 2990 nsContentPermissionUtils::GetContentPermissionRequestChildById( 2991 GetTabId()); 2992 2993 // Need to close undeleted ContentPermissionRequestChilds before tab is 2994 // closed. 2995 for (auto& permissionRequestChild : childArray) { 2996 auto* child = static_cast<RemotePermissionRequest*>(permissionRequestChild); 2997 child->Destroy(); 2998 } 2999 3000 if (mBrowserChildMessageManager) { 3001 // Message handlers are called from the event loop, so it better be safe to 3002 // run script. 3003 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); 3004 mBrowserChildMessageManager->DispatchTrustedEvent(u"unload"_ns); 3005 } 3006 3007 nsCOMPtr<nsIObserverService> observerService = 3008 mozilla::services::GetObserverService(); 3009 3010 observerService->RemoveObserver(this, BEFORE_FIRST_PAINT); 3011 3012 // XXX what other code in ~BrowserChild() should we be running here? 3013 DestroyWindow(); 3014 3015 // Bounce through the event loop once to allow any delayed teardown runnables 3016 // that were just generated to have a chance to run. 3017 nsCOMPtr<nsIRunnable> deleteRunnable = new DelayedDeleteRunnable(this); 3018 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(deleteRunnable)); 3019 3020 return IPC_OK(); 3021 } 3022 3023 mozilla::ipc::IPCResult BrowserChild::RecvRenderLayers(const bool& aEnabled) { 3024 auto clearPaintWhileInterruptingJS = MakeScopeExit([&] { 3025 // We might force a paint, or we might already have painted and this is a 3026 // no-op. In either case, once we exit this scope, we need to alert the 3027 // ProcessHangMonitor that we've finished responding to what might have 3028 // been a request to force paint. This is so that the BackgroundHangMonitor 3029 // for force painting can be made to wait again. 3030 if (aEnabled) { 3031 ProcessHangMonitor::ClearPaintWhileInterruptingJS(); 3032 } 3033 }); 3034 3035 if (aEnabled) { 3036 ProcessHangMonitor::MaybeStartPaintWhileInterruptingJS(); 3037 } 3038 3039 mRenderLayers = aEnabled; 3040 const bool wasVisible = IsVisible(); 3041 3042 UpdateVisibility(); 3043 3044 // If we just became visible, try to trigger a paint as soon as possible. 3045 const bool becameVisible = !wasVisible && IsVisible(); 3046 if (!becameVisible) { 3047 return IPC_OK(); 3048 } 3049 3050 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); 3051 if (!docShell) { 3052 return IPC_OK(); 3053 } 3054 3055 // We don't use BrowserChildBase::GetPresShell() here because that would 3056 // create a content viewer if one doesn't exist yet. Creating a content 3057 // viewer can cause JS to run, which we want to avoid. 3058 // nsIDocShell::GetPresShell returns null if no content viewer exists yet. 3059 RefPtr<PresShell> presShell = docShell->GetPresShell(); 3060 if (!presShell) { 3061 return IPC_OK(); 3062 } 3063 3064 if (nsIFrame* root = presShell->GetRootFrame()) { 3065 root->SchedulePaint(); 3066 } 3067 3068 // If we need to repaint, let's do that right away. No sense waiting until 3069 // we get back to the event loop again. We suppress the display port so 3070 // that we only paint what's visible. This ensures that the tab we're 3071 // switching to paints as quickly as possible. 3072 presShell->SuppressDisplayport(true); 3073 if (nsContentUtils::IsSafeToRunScript()) { 3074 WebWidget()->PaintNowIfNeeded(); 3075 } else { 3076 // NOTE: We want to call in even without a root frame (we might paint the 3077 // canvas background in that case). 3078 presShell->PaintAndRequestComposite(presShell->GetRootFrame(), 3079 mPuppetWidget->GetWindowRenderer(), 3080 PaintFlags::None); 3081 } 3082 presShell->SuppressDisplayport(false); 3083 return IPC_OK(); 3084 } 3085 3086 mozilla::ipc::IPCResult BrowserChild::RecvNavigateByKey( 3087 const bool& aForward, const bool& aForDocumentNavigation) { 3088 nsFocusManager* fm = nsFocusManager::GetFocusManager(); 3089 if (!fm) { 3090 return IPC_OK(); 3091 } 3092 3093 RefPtr<Element> result; 3094 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); 3095 3096 // Move to the first or last document. 3097 { 3098 uint32_t type = 3099 aForward 3100 ? (aForDocumentNavigation 3101 ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRSTDOC) 3102 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRST)) 3103 : (aForDocumentNavigation 3104 ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LASTDOC) 3105 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LAST)); 3106 uint32_t flags = nsIFocusManager::FLAG_BYKEY; 3107 if (aForward || aForDocumentNavigation) { 3108 flags |= nsIFocusManager::FLAG_NOSCROLL; 3109 } 3110 fm->MoveFocus(window, nullptr, type, flags, getter_AddRefs(result)); 3111 } 3112 3113 // No valid root element was found, so move to the first focusable element. 3114 if (!result && aForward && !aForDocumentNavigation) { 3115 fm->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_FIRST, 3116 nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result)); 3117 } 3118 3119 SendRequestFocus(false, CallerType::System); 3120 return IPC_OK(); 3121 } 3122 3123 bool BrowserChild::InitBrowserChildMessageManager() { 3124 mShouldSendWebProgressEventsToParent = true; 3125 3126 if (!mBrowserChildMessageManager) { 3127 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); 3128 NS_ENSURE_TRUE(window, false); 3129 nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler(); 3130 NS_ENSURE_TRUE(chromeHandler, false); 3131 3132 RefPtr<BrowserChildMessageManager> scope = mBrowserChildMessageManager = 3133 new BrowserChildMessageManager(this); 3134 3135 MOZ_ALWAYS_TRUE(nsMessageManagerScriptExecutor::Init()); 3136 3137 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler); 3138 if (NS_WARN_IF(!root)) { 3139 mBrowserChildMessageManager = nullptr; 3140 return false; 3141 } 3142 root->SetParentTarget(scope); 3143 } 3144 3145 if (!mTriedBrowserInit) { 3146 mTriedBrowserInit = true; 3147 } 3148 3149 return true; 3150 } 3151 3152 void BrowserChild::InitRenderingState( 3153 const TextureFactoryIdentifier& aTextureFactoryIdentifier, 3154 const layers::LayersId& aLayersId, 3155 const CompositorOptions& aCompositorOptions) { 3156 mPuppetWidget->InitIMEState(); 3157 3158 MOZ_ASSERT(aLayersId.IsValid()); 3159 mTextureFactoryIdentifier = aTextureFactoryIdentifier; 3160 3161 // Pushing layers transactions directly to a separate 3162 // compositor context. 3163 PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get(); 3164 if (!compositorChild) { 3165 mLayersConnected = Some(false); 3166 NS_WARNING("failed to get CompositorBridgeChild instance"); 3167 return; 3168 } 3169 3170 mCompositorOptions = Some(aCompositorOptions); 3171 3172 if (aLayersId.IsValid()) { 3173 StaticMutexAutoLock lock(sBrowserChildrenMutex); 3174 3175 if (!sBrowserChildren) { 3176 sBrowserChildren = new BrowserChildMap; 3177 } 3178 MOZ_ASSERT(!sBrowserChildren->Contains(uint64_t(aLayersId))); 3179 sBrowserChildren->InsertOrUpdate(uint64_t(aLayersId), this); 3180 mLayersId = aLayersId; 3181 } 3182 3183 // Depending on timing, we might paint too early and fall back to basic 3184 // layers. CreateRemoteLayerManager will destroy us if we manage to get a 3185 // remote layer manager though, so that's fine. 3186 MOZ_ASSERT(!mPuppetWidget->HasWindowRenderer() || 3187 mPuppetWidget->GetWindowRenderer()->GetBackendType() == 3188 layers::LayersBackend::LAYERS_NONE); 3189 bool success = false; 3190 if (mLayersConnected == Some(true)) { 3191 success = CreateRemoteLayerManager(compositorChild); 3192 } 3193 3194 if (success) { 3195 MOZ_ASSERT(mLayersConnected == Some(true)); 3196 // Succeeded to create "remote" layer manager 3197 ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier); 3198 gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier); 3199 InitAPZState(); 3200 } else { 3201 mLayersConnected = Some(false); 3202 } 3203 3204 nsCOMPtr<nsIObserverService> observerService = 3205 mozilla::services::GetObserverService(); 3206 3207 if (observerService) { 3208 observerService->AddObserver(this, BEFORE_FIRST_PAINT, false); 3209 } 3210 } 3211 3212 bool BrowserChild::CreateRemoteLayerManager( 3213 mozilla::layers::PCompositorBridgeChild* aCompositorChild) { 3214 MOZ_ASSERT(aCompositorChild); 3215 3216 return mPuppetWidget->CreateRemoteLayerManager( 3217 [&](WebRenderLayerManager* aLayerManager) -> bool { 3218 nsCString error; 3219 return aLayerManager->Initialize(aCompositorChild, 3220 wr::AsPipelineId(mLayersId), 3221 &mTextureFactoryIdentifier, error); 3222 }); 3223 } 3224 3225 void BrowserChild::InitAPZState() { 3226 if (!mCompositorOptions->UseAPZ()) { 3227 return; 3228 } 3229 auto* cbc = CompositorBridgeChild::Get(); 3230 3231 // Initialize the ApzcTreeManager. This takes multiple casts because of ugly 3232 // multiple inheritance. 3233 PAPZCTreeManagerChild* baseProtocol = 3234 cbc->SendPAPZCTreeManagerConstructor(mLayersId); 3235 if (!baseProtocol) { 3236 MOZ_ASSERT(false, 3237 "Allocating a TreeManager should not fail with APZ enabled"); 3238 return; 3239 } 3240 APZCTreeManagerChild* derivedProtocol = 3241 static_cast<APZCTreeManagerChild*>(baseProtocol); 3242 3243 mApzcTreeManager = RefPtr<IAPZCTreeManager>(derivedProtocol); 3244 3245 // Initialize the GeckoContentController for this tab. We don't hold a 3246 // reference because we don't need it. The ContentProcessController will hold 3247 // a reference to the tab, and will be destroyed by the compositor or ipdl 3248 // during destruction. 3249 RefPtr<GeckoContentController> contentController = 3250 new ContentProcessController(this); 3251 APZChild* apzChild = new APZChild(contentController); 3252 cbc->SendPAPZConstructor(apzChild, mLayersId); 3253 } 3254 3255 IPCResult BrowserChild::RecvUpdateEffects(const EffectsInfo& aEffects) { 3256 bool needInvalidate = false; 3257 if (mEffectsInfo.IsVisible() && aEffects.IsVisible() && 3258 mEffectsInfo != aEffects) { 3259 // If we are staying visible and either the visrect or scale changed we need 3260 // to invalidate 3261 needInvalidate = true; 3262 } 3263 3264 mEffectsInfo = aEffects; 3265 UpdateVisibility(); 3266 3267 if (needInvalidate) { 3268 if (nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation())) { 3269 // We don't use BrowserChildBase::GetPresShell() here because that would 3270 // create a content viewer if one doesn't exist yet. Creating a content 3271 // viewer can cause JS to run, which we want to avoid. 3272 // nsIDocShell::GetPresShell returns null if no content viewer exists yet. 3273 if (RefPtr<PresShell> presShell = docShell->GetPresShell()) { 3274 if (nsIFrame* root = presShell->GetRootFrame()) { 3275 root->InvalidateFrame(); 3276 } 3277 } 3278 } 3279 } 3280 3281 return IPC_OK(); 3282 } 3283 3284 bool BrowserChild::IsVisible() { 3285 return mPuppetWidget && mPuppetWidget->IsVisible(); 3286 } 3287 3288 void BrowserChild::UpdateVisibility() { 3289 const bool shouldBeVisible = [&] { 3290 // If we're known to be visibility: hidden / display: none, just return 3291 // false here, we're pretty sure we don't want to be considered visible 3292 // here. 3293 if (mBrowsingContext && mBrowsingContext->IsUnderHiddenEmbedderElement()) { 3294 return false; 3295 } 3296 // If we're explicitly told not to render layers, we're also invisible. 3297 if (!mRenderLayers) { 3298 return false; 3299 } 3300 if (!mIsTopLevel) { 3301 // For OOP iframes, include viewport visibility. 3302 if (!mEffectsInfo.IsVisible()) { 3303 return false; 3304 } 3305 // Also include activeness, unless we're artificially preserving layers. 3306 // An alternative to this would be to propagate mRenderLayers from the 3307 // parent, perhaps, so that it applies to the whole tree... 3308 if (!mIsPreservingLayers && mBrowsingContext && 3309 !mBrowsingContext->IsActive()) { 3310 return false; 3311 } 3312 } 3313 return true; 3314 }(); 3315 3316 const bool isVisible = IsVisible(); 3317 if (shouldBeVisible == isVisible) { 3318 return; 3319 } 3320 if (shouldBeVisible) { 3321 MakeVisible(); 3322 } else { 3323 MakeHidden(); 3324 } 3325 } 3326 3327 void BrowserChild::MakeVisible() { 3328 if (IsVisible()) { 3329 return; 3330 } 3331 3332 if (mPuppetWidget) { 3333 mPuppetWidget->Show(true); 3334 } 3335 3336 PresShellActivenessMaybeChanged(); 3337 } 3338 3339 void BrowserChild::MakeHidden() { 3340 if (!IsVisible()) { 3341 return; 3342 } 3343 3344 // Due to the nested event loop in ContentChild::ProvideWindowCommon, 3345 // it's possible to be told to become hidden before we're finished 3346 // setting up a layer manager. We should skip clearing cached layers 3347 // in that case, since doing so might accidentally put is into 3348 // BasicLayers mode. 3349 if (mPuppetWidget) { 3350 if (mPuppetWidget->HasWindowRenderer()) { 3351 ClearCachedResources(); 3352 } 3353 mPuppetWidget->Show(false); 3354 } 3355 3356 PresShellActivenessMaybeChanged(); 3357 } 3358 3359 IPCResult BrowserChild::RecvPreserveLayers(bool aPreserve) { 3360 mIsPreservingLayers = aPreserve; 3361 3362 UpdateVisibility(); 3363 PresShellActivenessMaybeChanged(); 3364 3365 return IPC_OK(); 3366 } 3367 3368 void BrowserChild::PresShellActivenessMaybeChanged() { 3369 // We don't use BrowserChildBase::GetPresShell() here because that would 3370 // create a content viewer if one doesn't exist yet. Creating a content 3371 // viewer can cause JS to run, which we want to avoid. 3372 // nsIDocShell::GetPresShell returns null if no content viewer exists yet. 3373 // 3374 // When this method is called we don't want to go through the browsing context 3375 // because we don't want to change the visibility state of the document, which 3376 // has side effects like firing events to content, unblocking media playback, 3377 // unthrottling timeouts... PresShell activeness has a lot less side effects. 3378 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); 3379 if (!docShell) { 3380 return; 3381 } 3382 RefPtr<PresShell> presShell = docShell->GetPresShell(); 3383 if (!presShell) { 3384 return; 3385 } 3386 presShell->ActivenessMaybeChanged(); 3387 } 3388 3389 NS_IMETHODIMP 3390 BrowserChild::GetMessageManager(ContentFrameMessageManager** aResult) { 3391 RefPtr<ContentFrameMessageManager> mm(mBrowserChildMessageManager); 3392 mm.forget(aResult); 3393 return *aResult ? NS_OK : NS_ERROR_FAILURE; 3394 } 3395 3396 void BrowserChild::SendRequestFocus(bool aCanFocus, CallerType aCallerType) { 3397 nsFocusManager* fm = nsFocusManager::GetFocusManager(); 3398 if (!fm) { 3399 return; 3400 } 3401 3402 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); 3403 if (!window) { 3404 return; 3405 } 3406 3407 BrowsingContext* focusedBC = fm->GetFocusedBrowsingContext(); 3408 if (focusedBC == window->GetBrowsingContext()) { 3409 // BrowsingContext has the focus already, do not request again. 3410 return; 3411 } 3412 3413 PBrowserChild::SendRequestFocus(aCanFocus, aCallerType); 3414 } 3415 3416 NS_IMETHODIMP 3417 BrowserChild::GetTabId(uint64_t* aId) { 3418 *aId = GetTabId(); 3419 return NS_OK; 3420 } 3421 3422 NS_IMETHODIMP 3423 BrowserChild::GetChromeOuterWindowID(uint64_t* aId) { 3424 *aId = ChromeOuterWindowID(); 3425 return NS_OK; 3426 } 3427 3428 bool BrowserChild::DoSendBlockingMessage( 3429 const nsAString& aMessage, StructuredCloneData& aData, 3430 nsTArray<UniquePtr<StructuredCloneData>>* aRetVal) { 3431 ClonedMessageData data; 3432 if (!BuildClonedMessageData(aData, data)) { 3433 return false; 3434 } 3435 return SendSyncMessage(PromiseFlatString(aMessage), data, aRetVal); 3436 } 3437 3438 nsresult BrowserChild::DoSendAsyncMessage(const nsAString& aMessage, 3439 StructuredCloneData& aData) { 3440 ClonedMessageData data; 3441 if (!BuildClonedMessageData(aData, data)) { 3442 return NS_ERROR_DOM_DATA_CLONE_ERR; 3443 } 3444 if (!SendAsyncMessage(PromiseFlatString(aMessage), data)) { 3445 return NS_ERROR_UNEXPECTED; 3446 } 3447 return NS_OK; 3448 } 3449 3450 /* static */ 3451 nsTArray<RefPtr<BrowserChild>> BrowserChild::GetAll() { 3452 StaticMutexAutoLock lock(sBrowserChildrenMutex); 3453 3454 if (!sBrowserChildren) { 3455 return {}; 3456 } 3457 3458 return ToTArray<nsTArray<RefPtr<BrowserChild>>>(sBrowserChildren->Values()); 3459 } 3460 3461 BrowserChild* BrowserChild::GetFrom(PresShell* aPresShell) { 3462 Document* doc = aPresShell->GetDocument(); 3463 if (!doc) { 3464 return nullptr; 3465 } 3466 nsCOMPtr<nsIDocShell> docShell(doc->GetDocShell()); 3467 return GetFrom(docShell); 3468 } 3469 3470 BrowserChild* BrowserChild::GetFrom(layers::LayersId aLayersId) { 3471 StaticMutexAutoLock lock(sBrowserChildrenMutex); 3472 if (!sBrowserChildren) { 3473 return nullptr; 3474 } 3475 return sBrowserChildren->Get(uint64_t(aLayersId)); 3476 } 3477 3478 void BrowserChild::DidComposite(mozilla::layers::TransactionId aTransactionId, 3479 const TimeStamp& aCompositeStart, 3480 const TimeStamp& aCompositeEnd) { 3481 MOZ_ASSERT(mPuppetWidget); 3482 RefPtr<WebRenderLayerManager> lm = 3483 mPuppetWidget->GetWindowRenderer()->AsWebRender(); 3484 MOZ_ASSERT(lm); 3485 3486 if (lm) { 3487 lm->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd); 3488 } 3489 } 3490 3491 void BrowserChild::ClearCachedResources() { 3492 MOZ_ASSERT(mPuppetWidget); 3493 RefPtr<WebRenderLayerManager> lm = 3494 mPuppetWidget->GetWindowRenderer()->AsWebRender(); 3495 if (lm) { 3496 lm->ClearCachedResources(); 3497 } 3498 3499 if (nsCOMPtr<Document> document = GetTopLevelDocument()) { 3500 nsPresContext* presContext = document->GetPresContext(); 3501 if (presContext) { 3502 presContext->NotifyPaintStatusReset(); 3503 } 3504 } 3505 } 3506 3507 void BrowserChild::SchedulePaint() { 3508 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); 3509 if (!docShell) { 3510 return; 3511 } 3512 3513 // We don't use BrowserChildBase::GetPresShell() here because that would 3514 // create a content viewer if one doesn't exist yet. Creating a content viewer 3515 // can cause JS to run, which we want to avoid. nsIDocShell::GetPresShell 3516 // returns null if no content viewer exists yet. 3517 if (RefPtr<PresShell> presShell = docShell->GetPresShell()) { 3518 if (nsIFrame* root = presShell->GetRootFrame()) { 3519 root->SchedulePaint(); 3520 } 3521 } 3522 } 3523 3524 void SkipViewTransitionsAfterRenderingReset(Document& aDocument) { 3525 if (RefPtr<ViewTransition> transition = aDocument.GetActiveViewTransition()) { 3526 transition->SkipTransition(SkipTransitionReason::ResetRendering); 3527 } 3528 3529 aDocument.EnumerateSubDocuments([&](Document& aSubDoc) { 3530 SkipViewTransitionsAfterRenderingReset(aSubDoc); 3531 return CallState::Continue; 3532 }); 3533 } 3534 3535 void BrowserChild::ReinitRendering() { 3536 MOZ_ASSERT(mLayersId.IsValid()); 3537 3538 if (RefPtr<Document> doc = GetTopLevelDocument()) { 3539 SkipViewTransitionsAfterRenderingReset(*doc); 3540 } 3541 3542 // In some cases, like when we create a windowless browser, 3543 // RemoteLayerTreeOwner/BrowserChild is not connected to a compositor. 3544 if (mLayersConnectRequested.isNothing() || 3545 mLayersConnectRequested == Some(false)) { 3546 return; 3547 } 3548 3549 // Before we establish a new PLayerTransaction, we must connect our layer tree 3550 // id, CompositorBridge, and the widget compositor all together again. 3551 // Normally this happens in BrowserParent before BrowserChild is given 3552 // rendering information. 3553 // 3554 // In this case, we will send a sync message to our BrowserParent, which in 3555 // turn will send a sync message to the Compositor of the widget owning this 3556 // tab. This guarantees the correct association is in place before our 3557 // PLayerTransaction constructor message arrives on the cross-process 3558 // compositor bridge. 3559 CompositorOptions options; 3560 SendEnsureLayersConnected(&options); 3561 mCompositorOptions = Some(options); 3562 3563 bool success = false; 3564 RefPtr<CompositorBridgeChild> cb = CompositorBridgeChild::Get(); 3565 3566 if (cb) { 3567 success = CreateRemoteLayerManager(cb); 3568 } 3569 3570 if (!success) { 3571 NS_WARNING("failed to recreate layer manager"); 3572 return; 3573 } 3574 3575 mLayersConnected = Some(true); 3576 ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier); 3577 gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier); 3578 3579 InitAPZState(); 3580 if (nsCOMPtr<Document> doc = GetTopLevelDocument()) { 3581 doc->NotifyLayerManagerRecreated(); 3582 } 3583 3584 if (mRenderLayers) { 3585 SchedulePaint(); 3586 } 3587 } 3588 3589 void BrowserChild::ReinitRenderingForDeviceReset() { 3590 RefPtr<WebRenderLayerManager> lm = 3591 mPuppetWidget->GetWindowRenderer()->AsWebRender(); 3592 if (lm) { 3593 lm->DoDestroy(/* aIsSync */ true); 3594 } 3595 3596 // Proceed with destroying and recreating the layer manager. 3597 ReinitRendering(); 3598 } 3599 3600 NS_IMETHODIMP 3601 BrowserChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, 3602 const nsAString& aTipText, 3603 const nsAString& aTipDir) { 3604 nsString str(aTipText); 3605 nsString dir(aTipDir); 3606 SendShowTooltip(aXCoords, aYCoords, str, dir); 3607 return NS_OK; 3608 } 3609 3610 NS_IMETHODIMP 3611 BrowserChild::OnHideTooltip() { 3612 SendHideTooltip(); 3613 return NS_OK; 3614 } 3615 3616 void BrowserChild::NotifyJankedAnimations( 3617 const nsTArray<uint64_t>& aJankedAnimations) { 3618 MOZ_ASSERT(mPuppetWidget); 3619 RefPtr<WebRenderLayerManager> lm = 3620 mPuppetWidget->GetWindowRenderer()->AsWebRender(); 3621 if (lm) { 3622 lm->UpdatePartialPrerenderedAnimations(aJankedAnimations); 3623 } 3624 } 3625 3626 mozilla::ipc::IPCResult BrowserChild::RecvUIResolutionChanged( 3627 const float& aDpi, const int32_t& aRounding, const double& aScale) { 3628 const LayoutDeviceIntSize oldInnerSize = GetInnerSize(); 3629 if (aDpi > 0) { 3630 mPuppetWidget->UpdateBackingScaleCache(aDpi, aRounding, aScale); 3631 } 3632 3633 const LayoutDeviceIntSize innerSize = GetInnerSize(); 3634 if (mHasValidInnerSize && oldInnerSize != innerSize) { 3635 // See RecvUpdateDimensions for the order of these operations. 3636 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation()); 3637 baseWin->SetPositionAndSize(0, 0, innerSize.width, innerSize.height, 3638 nsIBaseWindow::eRepaint); 3639 3640 const LayoutDeviceIntRect widgetRect( 3641 GetOuterRect().TopLeft() + mClientOffset + mChromeOffset, innerSize); 3642 mPuppetWidget->Resize(widgetRect / mPuppetWidget->GetDesktopToDeviceScale(), 3643 true); 3644 } 3645 3646 nsCOMPtr<Document> document(GetTopLevelDocument()); 3647 RefPtr<nsPresContext> presContext = 3648 document ? document->GetPresContext() : nullptr; 3649 if (presContext) { 3650 presContext->UIResolutionChangedSync(); 3651 } 3652 3653 return IPC_OK(); 3654 } 3655 3656 mozilla::ipc::IPCResult BrowserChild::RecvTransparencyChanged( 3657 const bool& aIsTransparent) { 3658 mIsTransparent = aIsTransparent; 3659 SchedulePaint(); 3660 return IPC_OK(); 3661 } 3662 3663 mozilla::ipc::IPCResult BrowserChild::RecvSafeAreaInsetsChanged( 3664 const mozilla::LayoutDeviceIntMargin& aSafeAreaInsets) { 3665 mPuppetWidget->UpdateSafeAreaInsets(aSafeAreaInsets); 3666 3667 LayoutDeviceIntMargin currentSafeAreaInsets; 3668 // aSafeAreaInsets is for current screen. But we have to calculate safe insets 3669 // for content window. 3670 LayoutDeviceIntRect outerRect = GetOuterRect(); 3671 RefPtr<Screen> screen = widget::ScreenManager::GetSingleton().ScreenForRect( 3672 RoundedToInt(outerRect / mPuppetWidget->GetDesktopToDeviceScale())); 3673 if (screen) { 3674 LayoutDeviceIntRect windowRect = outerRect + mClientOffset + mChromeOffset; 3675 currentSafeAreaInsets = nsContentUtils::GetWindowSafeAreaInsets( 3676 screen, aSafeAreaInsets, windowRect); 3677 } 3678 3679 if (nsCOMPtr<Document> document = GetTopLevelDocument()) { 3680 if (nsPresContext* presContext = document->GetPresContext()) { 3681 presContext->SetSafeAreaInsets(currentSafeAreaInsets); 3682 } 3683 } 3684 3685 // https://github.com/w3c/csswg-drafts/issues/4670 3686 // Actually we don't set this value on sub document. This behaviour is 3687 // same as Blink that safe area insets isn't set on sub document. 3688 3689 return IPC_OK(); 3690 } 3691 3692 mozilla::ipc::IPCResult BrowserChild::RecvAllowScriptsToClose() { 3693 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation()); 3694 if (window) { 3695 nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose(); 3696 } 3697 return IPC_OK(); 3698 } 3699 3700 mozilla::ipc::IPCResult BrowserChild::RecvReleaseAllPointerCapture() { 3701 PointerEventHandler::ReleaseAllPointerCapture(); 3702 return IPC_OK(); 3703 } 3704 3705 mozilla::ipc::IPCResult BrowserChild::RecvReleasePointerLock() { 3706 PointerLockManager::Unlock("BrowserChild::RecvReleasePointerLock"); 3707 return IPC_OK(); 3708 } 3709 3710 PPaymentRequestChild* BrowserChild::AllocPPaymentRequestChild() { 3711 MOZ_CRASH( 3712 "We should never be manually allocating PPaymentRequestChild actors"); 3713 return nullptr; 3714 } 3715 3716 bool BrowserChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor) { 3717 delete actor; 3718 return true; 3719 } 3720 3721 LayoutDeviceIntSize BrowserChild::GetInnerSize() { 3722 return RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale()); 3723 }; 3724 3725 Maybe<nsRect> BrowserChild::GetVisibleRect() const { 3726 if (mIsTopLevel) { 3727 // We are conservative about visible rects for top-level browsers to avoid 3728 // artifacts when resizing 3729 return Nothing(); 3730 } 3731 return mEffectsInfo.mVisibleRect; 3732 } 3733 3734 Maybe<LayoutDeviceRect> 3735 BrowserChild::GetTopLevelViewportVisibleRectInSelfCoords() const { 3736 if (mIsTopLevel) { 3737 return Nothing(); 3738 } 3739 3740 if (!mChildToParentConversionMatrix) { 3741 // We have no way to tell this remote document visible rect right now. 3742 return Nothing(); 3743 } 3744 3745 Maybe<LayoutDeviceToLayoutDeviceMatrix4x4> inverse = 3746 mChildToParentConversionMatrix->MaybeInverse(); 3747 if (!inverse) { 3748 return Nothing(); 3749 } 3750 3751 // Convert the remote document visible rect to the coordinate system of the 3752 // iframe document. 3753 Maybe<LayoutDeviceRect> rect = UntransformBy( 3754 *inverse, 3755 ViewAs<LayoutDevicePixel>( 3756 mTopLevelViewportVisibleRectInBrowserCoords, 3757 PixelCastJustification::ContentProcessIsLayerInUiProcess), 3758 LayoutDeviceRect::MaxIntRect()); 3759 if (!rect) { 3760 return Nothing(); 3761 } 3762 3763 return rect; 3764 } 3765 3766 LayoutDeviceIntRect BrowserChild::GetOuterRect() { 3767 return RoundedToInt(mUnscaledOuterRect * mPuppetWidget->GetDefaultScale()); 3768 } 3769 3770 void BrowserChild::PaintWhileInterruptingJS() { 3771 if (!IPCOpen() || !mPuppetWidget || !mPuppetWidget->HasWindowRenderer()) { 3772 // Don't bother doing anything now. Better to wait until we receive the 3773 // message on the PContent channel. 3774 return; 3775 } 3776 3777 MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsSafeToRunScript()); 3778 nsAutoScriptBlocker scriptBlocker; 3779 RecvRenderLayers(/* aEnabled = */ true); 3780 } 3781 3782 void BrowserChild::UnloadLayersWhileInterruptingJS() { 3783 if (!IPCOpen() || !mPuppetWidget || !mPuppetWidget->HasWindowRenderer()) { 3784 // Don't bother doing anything now. Better to wait until we receive the 3785 // message on the PContent channel. 3786 return; 3787 } 3788 3789 MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsSafeToRunScript()); 3790 nsAutoScriptBlocker scriptBlocker; 3791 RecvRenderLayers(/* aEnabled = */ false); 3792 } 3793 3794 nsresult BrowserChild::CanCancelContentJS( 3795 nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex, 3796 nsIURI* aNavigationURI, int32_t aEpoch, bool* aCanCancel) { 3797 nsresult rv; 3798 *aCanCancel = false; 3799 3800 if (aEpoch <= mCancelContentJSEpoch) { 3801 // The next page loaded before we got here, so we shouldn't try to cancel 3802 // the content JS. 3803 return NS_OK; 3804 } 3805 3806 // If we have session history in the parent we've already performed 3807 // the checks following, so we can return early. 3808 if (mozilla::SessionHistoryInParent()) { 3809 *aCanCancel = true; 3810 return NS_OK; 3811 } 3812 3813 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation()); 3814 nsCOMPtr<nsISHistory> history; 3815 if (docShell) { 3816 history = nsDocShell::Cast(docShell)->GetSessionHistory()->LegacySHistory(); 3817 } 3818 3819 if (!history) { 3820 return NS_ERROR_FAILURE; 3821 } 3822 3823 int32_t current; 3824 rv = history->GetIndex(¤t); 3825 NS_ENSURE_SUCCESS(rv, rv); 3826 3827 if (current == -1) { 3828 // This tab has no history! Just return. 3829 return NS_OK; 3830 } 3831 3832 nsCOMPtr<nsISHEntry> entry; 3833 rv = history->GetEntryAtIndex(current, getter_AddRefs(entry)); 3834 NS_ENSURE_SUCCESS(rv, rv); 3835 3836 nsCOMPtr<nsIURI> currentURI = entry->GetURI(); 3837 if (!net::SchemeIsHttpOrHttps(currentURI) && !currentURI->SchemeIs("file")) { 3838 // Only cancel content JS for http(s) and file URIs. Other URIs are probably 3839 // internal and we should just let them run to completion. 3840 return NS_OK; 3841 } 3842 3843 if (aNavigationType == nsIRemoteTab::NAVIGATE_BACK) { 3844 aNavigationIndex = current - 1; 3845 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_FORWARD) { 3846 aNavigationIndex = current + 1; 3847 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_URL) { 3848 if (!aNavigationURI) { 3849 return NS_ERROR_FAILURE; 3850 } 3851 3852 if (aNavigationURI->SchemeIs("javascript")) { 3853 // "javascript:" URIs don't (necessarily) trigger navigation to a 3854 // different page, so don't allow the current page's JS to terminate. 3855 return NS_OK; 3856 } 3857 3858 // If navigating directly to a URL (e.g. via hitting Enter in the location 3859 // bar), then we can cancel anytime the next URL is different from the 3860 // current, *excluding* the ref ("#"). 3861 bool equals; 3862 rv = currentURI->EqualsExceptRef(aNavigationURI, &equals); 3863 NS_ENSURE_SUCCESS(rv, rv); 3864 *aCanCancel = !equals; 3865 return NS_OK; 3866 } 3867 // Note: aNavigationType may also be NAVIGATE_INDEX, in which case we don't 3868 // need to do anything special. 3869 3870 int32_t delta = aNavigationIndex > current ? 1 : -1; 3871 for (int32_t i = current + delta; i != aNavigationIndex + delta; i += delta) { 3872 nsCOMPtr<nsISHEntry> nextEntry; 3873 // If `i` happens to be negative, this call will fail (which is what we 3874 // would want to happen). 3875 rv = history->GetEntryAtIndex(i, getter_AddRefs(nextEntry)); 3876 NS_ENSURE_SUCCESS(rv, rv); 3877 3878 nsCOMPtr<nsISHEntry> laterEntry = delta == 1 ? nextEntry : entry; 3879 nsCOMPtr<nsIURI> thisURI = entry->GetURI(); 3880 nsCOMPtr<nsIURI> nextURI = nextEntry->GetURI(); 3881 3882 // If we changed origin and the load wasn't in a subframe, we know it was 3883 // a full document load, so we can cancel the content JS safely. 3884 if (!laterEntry->GetIsSubFrame()) { 3885 nsAutoCString thisHost; 3886 rv = thisURI->GetPrePath(thisHost); 3887 NS_ENSURE_SUCCESS(rv, rv); 3888 3889 nsAutoCString nextHost; 3890 rv = nextURI->GetPrePath(nextHost); 3891 NS_ENSURE_SUCCESS(rv, rv); 3892 3893 if (!thisHost.Equals(nextHost)) { 3894 *aCanCancel = true; 3895 return NS_OK; 3896 } 3897 } 3898 3899 entry = nextEntry; 3900 } 3901 3902 return NS_OK; 3903 } 3904 3905 NS_IMETHODIMP BrowserChild::OnStateChange(nsIWebProgress* aWebProgress, 3906 nsIRequest* aRequest, 3907 uint32_t aStateFlags, 3908 nsresult aStatus) { 3909 if (!IPCOpen() || mDestroyed || !mShouldSendWebProgressEventsToParent) { 3910 return NS_OK; 3911 } 3912 3913 // We shouldn't need to notify the parent of redirect state changes, since 3914 // with DocumentChannel that only happens when we switch to the real channel, 3915 // and that's an implementation detail that we can hide. 3916 if (aStateFlags & nsIWebProgressListener::STATE_IS_REDIRECTED_DOCUMENT) { 3917 return NS_OK; 3918 } 3919 3920 // Our OnStateChange call must have provided the nsIDocShell which the source 3921 // comes from. We'll use this to locate the corresponding BrowsingContext in 3922 // the parent process. 3923 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress); 3924 if (!docShell) { 3925 MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?"); 3926 return NS_ERROR_UNEXPECTED; 3927 } 3928 3929 WebProgressData webProgressData; 3930 Maybe<WebProgressStateChangeData> stateChangeData; 3931 RequestData requestData; 3932 3933 MOZ_TRY(PrepareProgressListenerData(aWebProgress, aRequest, webProgressData, 3934 requestData)); 3935 3936 RefPtr<BrowsingContext> browsingContext = docShell->GetBrowsingContext(); 3937 if (browsingContext->IsTopContent()) { 3938 stateChangeData.emplace(); 3939 3940 stateChangeData->isNavigating() = docShell->GetIsNavigating(); 3941 stateChangeData->mayEnableCharacterEncodingMenu() = 3942 docShell->GetMayEnableCharacterEncodingMenu(); 3943 3944 RefPtr<Document> document = browsingContext->GetExtantDocument(); 3945 if (document && aStateFlags & nsIWebProgressListener::STATE_STOP) { 3946 document->GetContentType(stateChangeData->contentType()); 3947 document->GetCharacterSet(stateChangeData->charset()); 3948 stateChangeData->documentURI() = document->GetDocumentURIObject(); 3949 } else { 3950 stateChangeData->contentType().SetIsVoid(true); 3951 stateChangeData->charset().SetIsVoid(true); 3952 } 3953 } 3954 3955 (void)SendOnStateChange(webProgressData, requestData, aStateFlags, aStatus, 3956 stateChangeData); 3957 3958 return NS_OK; 3959 } 3960 3961 NS_IMETHODIMP BrowserChild::OnProgressChange(nsIWebProgress* aWebProgress, 3962 nsIRequest* aRequest, 3963 int32_t aCurSelfProgress, 3964 int32_t aMaxSelfProgress, 3965 int32_t aCurTotalProgress, 3966 int32_t aMaxTotalProgress) { 3967 if (!IPCOpen() || mDestroyed || !mShouldSendWebProgressEventsToParent) { 3968 return NS_OK; 3969 } 3970 3971 // FIXME: We currently ignore ProgressChange events from out-of-process 3972 // subframes both here and in BrowserParent. We may want to change this 3973 // behaviour in the future. 3974 if (!GetBrowsingContext()->IsTopContent()) { 3975 return NS_OK; 3976 } 3977 3978 // NOTE: ProgressChange notifications delivered here are filtered by 3979 // nsBrowserStatusFilter, which passes meaningless values for all other 3980 // arguments, so they are ignored here. 3981 (void)SendOnProgressChange(aCurTotalProgress, aMaxTotalProgress); 3982 3983 return NS_OK; 3984 } 3985 3986 NS_IMETHODIMP BrowserChild::OnLocationChange(nsIWebProgress* aWebProgress, 3987 nsIRequest* aRequest, 3988 nsIURI* aLocation, 3989 uint32_t aFlags) { 3990 if (!IPCOpen() || mDestroyed || !mShouldSendWebProgressEventsToParent) { 3991 return NS_OK; 3992 } 3993 3994 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress); 3995 if (!docShell) { 3996 MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?"); 3997 return NS_ERROR_UNEXPECTED; 3998 } 3999 4000 RefPtr<BrowsingContext> browsingContext = docShell->GetBrowsingContext(); 4001 RefPtr<Document> document = browsingContext->GetExtantDocument(); 4002 if (!document) { 4003 return NS_OK; 4004 } 4005 4006 WebProgressData webProgressData; 4007 RequestData requestData; 4008 4009 MOZ_TRY(PrepareProgressListenerData(aWebProgress, aRequest, webProgressData, 4010 requestData)); 4011 4012 Maybe<WebProgressLocationChangeData> locationChangeData; 4013 4014 bool canGoBack = false; 4015 bool canGoBackIgnoringUserInteraction = false; 4016 bool canGoForward = false; 4017 if (!mozilla::SessionHistoryInParent()) { 4018 MOZ_TRY(WebNavigation()->GetCanGoBack(&canGoBack)); 4019 MOZ_TRY(WebNavigation()->GetCanGoBackIgnoringUserInteraction( 4020 &canGoBackIgnoringUserInteraction)); 4021 MOZ_TRY(WebNavigation()->GetCanGoForward(&canGoForward)); 4022 } 4023 4024 if (browsingContext->IsTopContent()) { 4025 MOZ_ASSERT( 4026 browsingContext == GetBrowsingContext(), 4027 "Toplevel content BrowsingContext which isn't GetBrowsingContext()?"); 4028 4029 locationChangeData.emplace(); 4030 4031 document->GetContentType(locationChangeData->contentType()); 4032 locationChangeData->isNavigating() = docShell->GetIsNavigating(); 4033 locationChangeData->documentURI() = document->GetDocumentURIObject(); 4034 document->GetTitle(locationChangeData->title()); 4035 document->GetCharacterSet(locationChangeData->charset()); 4036 4037 locationChangeData->mayEnableCharacterEncodingMenu() = 4038 docShell->GetMayEnableCharacterEncodingMenu(); 4039 4040 locationChangeData->contentPrincipal() = document->NodePrincipal(); 4041 locationChangeData->contentPartitionedPrincipal() = 4042 document->PartitionedPrincipal(); 4043 locationChangeData->policyContainer() = document->GetPolicyContainer(); 4044 locationChangeData->referrerInfo() = document->ReferrerInfo(); 4045 locationChangeData->isSyntheticDocument() = document->IsSyntheticDocument(); 4046 4047 if (nsCOMPtr<nsILoadGroup> loadGroup = document->GetDocumentLoadGroup()) { 4048 uint64_t requestContextID = 0; 4049 MOZ_TRY(loadGroup->GetRequestContextID(&requestContextID)); 4050 locationChangeData->requestContextID() = Some(requestContextID); 4051 } 4052 4053 #ifdef MOZ_CRASHREPORTER 4054 if (CrashReporter::GetEnabled()) { 4055 nsCOMPtr<nsIURI> annotationURI; 4056 4057 nsresult rv = 4058 NS_MutateURI(aLocation).SetUserPass(""_ns).Finalize(annotationURI); 4059 4060 if (NS_FAILED(rv)) { 4061 // Ignore failures on about: URIs. 4062 annotationURI = aLocation; 4063 } 4064 4065 CrashReporter::RecordAnnotationNSCString( 4066 CrashReporter::Annotation::URL, annotationURI->GetSpecOrDefault()); 4067 } 4068 #endif 4069 } 4070 4071 (void)SendOnLocationChange(webProgressData, requestData, aLocation, aFlags, 4072 canGoBack, canGoBackIgnoringUserInteraction, 4073 canGoForward, locationChangeData); 4074 4075 return NS_OK; 4076 } 4077 4078 NS_IMETHODIMP BrowserChild::OnStatusChange(nsIWebProgress* aWebProgress, 4079 nsIRequest* aRequest, 4080 nsresult aStatus, 4081 const char16_t* aMessage) { 4082 if (!IPCOpen() || mDestroyed || !mShouldSendWebProgressEventsToParent) { 4083 return NS_OK; 4084 } 4085 4086 // NOTE: StatusChange notifications delivered here are filtered by 4087 // nsBrowserStatusFilter, which passes meaningless values for all other 4088 // arguments, so they are ignored here. 4089 (void)SendOnStatusChange(nsDependentString(aMessage)); 4090 4091 return NS_OK; 4092 } 4093 4094 NS_IMETHODIMP BrowserChild::OnSecurityChange(nsIWebProgress* aWebProgress, 4095 nsIRequest* aRequest, 4096 uint32_t aState) { 4097 // Security changes are now handled entirely in the parent process 4098 // so we don't need to worry about forwarding them (and we shouldn't 4099 // be receiving any to forward). 4100 return NS_OK; 4101 } 4102 4103 NS_IMETHODIMP BrowserChild::OnContentBlockingEvent(nsIWebProgress* aWebProgress, 4104 nsIRequest* aRequest, 4105 uint32_t aEvent) { 4106 // The OnContentBlockingEvent only happenes in the parent process. It should 4107 // not be seen in the content process. 4108 MOZ_DIAGNOSTIC_ASSERT( 4109 false, "OnContentBlockingEvent should not be seen in content process."); 4110 return NS_ERROR_NOT_IMPLEMENTED; 4111 } 4112 4113 NS_IMETHODIMP BrowserChild::NotifyNavigationFinished() { 4114 (void)SendNavigationFinished(); 4115 return NS_OK; 4116 } 4117 4118 nsresult BrowserChild::PrepareRequestData(nsIRequest* aRequest, 4119 RequestData& aRequestData) { 4120 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); 4121 if (!channel) { 4122 aRequestData.requestURI() = nullptr; 4123 return NS_OK; 4124 } 4125 4126 nsresult rv = channel->GetURI(getter_AddRefs(aRequestData.requestURI())); 4127 NS_ENSURE_SUCCESS(rv, rv); 4128 4129 rv = channel->GetOriginalURI( 4130 getter_AddRefs(aRequestData.originalRequestURI())); 4131 NS_ENSURE_SUCCESS(rv, rv); 4132 4133 rv = channel->GetCanceledReason(aRequestData.canceledReason()); 4134 NS_ENSURE_SUCCESS(rv, rv); 4135 4136 nsCOMPtr<nsIClassifiedChannel> classifiedChannel = do_QueryInterface(channel); 4137 if (classifiedChannel) { 4138 rv = classifiedChannel->GetMatchedList(aRequestData.matchedList()); 4139 NS_ENSURE_SUCCESS(rv, rv); 4140 } 4141 return NS_OK; 4142 } 4143 4144 nsresult BrowserChild::PrepareProgressListenerData( 4145 nsIWebProgress* aWebProgress, nsIRequest* aRequest, 4146 WebProgressData& aWebProgressData, RequestData& aRequestData) { 4147 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress); 4148 if (!docShell) { 4149 MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?"); 4150 return NS_ERROR_UNEXPECTED; 4151 } 4152 4153 aWebProgressData.browsingContext() = docShell->GetBrowsingContext(); 4154 nsresult rv = aWebProgress->GetLoadType(&aWebProgressData.loadType()); 4155 NS_ENSURE_SUCCESS(rv, rv); 4156 4157 return PrepareRequestData(aRequest, aRequestData); 4158 } 4159 4160 void BrowserChild::UpdateSessionStore() { 4161 if (mSessionStoreChild) { 4162 mSessionStoreChild->UpdateSessionStore(); 4163 } 4164 } 4165 4166 #ifdef XP_WIN 4167 RefPtr<PBrowserChild::IsWindowSupportingProtectedMediaPromise> 4168 BrowserChild::DoesWindowSupportProtectedMedia() { 4169 MOZ_ASSERT( 4170 NS_IsMainThread(), 4171 "Protected media support check should be done on main thread only."); 4172 if (mWindowSupportsProtectedMedia) { 4173 // If we've already checked and have a cached result, resolve with that. 4174 return IsWindowSupportingProtectedMediaPromise::CreateAndResolve( 4175 mWindowSupportsProtectedMedia.value(), __func__); 4176 } 4177 RefPtr<BrowserChild> self = this; 4178 // We chain off the promise rather than passing it directly so we can cache 4179 // the result and use that for future calls. 4180 return SendIsWindowSupportingProtectedMedia(ChromeOuterWindowID()) 4181 ->Then( 4182 GetCurrentSerialEventTarget(), __func__, 4183 [self](bool isSupported) { 4184 // If a result was cached while this check was inflight, ensure the 4185 // results match. 4186 MOZ_ASSERT_IF( 4187 self->mWindowSupportsProtectedMedia, 4188 self->mWindowSupportsProtectedMedia.value() == isSupported); 4189 // Cache the response as it will not change during the lifetime 4190 // of this object. 4191 self->mWindowSupportsProtectedMedia = Some(isSupported); 4192 return IsWindowSupportingProtectedMediaPromise::CreateAndResolve( 4193 self->mWindowSupportsProtectedMedia.value(), __func__); 4194 }, 4195 [](ResponseRejectReason reason) { 4196 return IsWindowSupportingProtectedMediaPromise::CreateAndReject( 4197 reason, __func__); 4198 }); 4199 } 4200 #endif 4201 4202 void BrowserChild::NotifyContentBlockingEvent( 4203 uint32_t aEvent, nsIChannel* aChannel, bool aBlocked, 4204 const nsACString& aTrackingOrigin, 4205 const nsTArray<nsCString>& aTrackingFullHashes, 4206 const Maybe< 4207 mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason>& 4208 aReason, 4209 const Maybe<CanvasFingerprintingEvent>& aCanvasFingerprintingEvent) { 4210 if (!IPCOpen()) { 4211 return; 4212 } 4213 4214 RequestData requestData; 4215 if (NS_SUCCEEDED(PrepareRequestData(aChannel, requestData))) { 4216 (void)SendNotifyContentBlockingEvent( 4217 aEvent, requestData, aBlocked, PromiseFlatCString(aTrackingOrigin), 4218 aTrackingFullHashes, aReason, aCanvasFingerprintingEvent); 4219 } 4220 } 4221 4222 NS_IMETHODIMP 4223 BrowserChild::ContentTransformsReceived(JSContext* aCx, 4224 dom::Promise** aPromise) { 4225 auto* globalObject = xpc::CurrentNativeGlobal(aCx); 4226 ErrorResult rv; 4227 if (mChildToParentConversionMatrix) { 4228 // Already received content transforms 4229 RefPtr<Promise> promise = 4230 Promise::CreateResolvedWithUndefined(globalObject, rv); 4231 promise.forget(aPromise); 4232 return rv.StealNSResult(); 4233 } 4234 4235 if (!mContentTransformPromise) { 4236 mContentTransformPromise = Promise::Create(globalObject, rv); 4237 } 4238 4239 MOZ_ASSERT(globalObject == mContentTransformPromise->GetGlobalObject()); 4240 NS_IF_ADDREF(*aPromise = mContentTransformPromise); 4241 return rv.StealNSResult(); 4242 } 4243 4244 already_AddRefed<nsIDragSession> BrowserChild::GetDragSession() { 4245 return RefPtr(mDragSession).forget(); 4246 } 4247 4248 void BrowserChild::SetDragSession(nsIDragSession* aSession) { 4249 mDragSession = aSession; 4250 } 4251 4252 LazyLogModule gPointerRawUpdateEventListenersLog( 4253 "PointerRawUpdateEventListeners"); 4254 4255 void BrowserChild::OnPointerRawUpdateEventListenerAdded( 4256 const nsPIDOMWindowInner* aWindow) { 4257 mPointerRawUpdateWindowCount++; 4258 MOZ_LOG(gPointerRawUpdateEventListenersLog, LogLevel::Info, 4259 ("Added for %p (total: %u)", aWindow, mPointerRawUpdateWindowCount)); 4260 } 4261 4262 void BrowserChild::OnPointerRawUpdateEventListenerRemoved( 4263 const nsPIDOMWindowInner* aWindow) { 4264 MOZ_ASSERT(mPointerRawUpdateWindowCount); 4265 if (MOZ_LIKELY(mPointerRawUpdateWindowCount)) { 4266 mPointerRawUpdateWindowCount--; 4267 } 4268 MOZ_LOG(gPointerRawUpdateEventListenersLog, LogLevel::Info, 4269 ("Removed for %p (remaining: %u)", aWindow, 4270 mPointerRawUpdateWindowCount)); 4271 } 4272 4273 BrowserChildMessageManager::BrowserChildMessageManager( 4274 BrowserChild* aBrowserChild) 4275 : ContentFrameMessageManager(new nsFrameMessageManager(aBrowserChild)), 4276 mBrowserChild(aBrowserChild) {} 4277 4278 BrowserChildMessageManager::~BrowserChildMessageManager() = default; 4279 4280 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowserChildMessageManager) 4281 4282 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BrowserChildMessageManager, 4283 DOMEventTargetHelper) 4284 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager); 4285 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild); 4286 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE 4287 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 4288 4289 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BrowserChildMessageManager, 4290 DOMEventTargetHelper) 4291 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager) 4292 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild) 4293 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 4294 4295 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChildMessageManager) 4296 NS_INTERFACE_MAP_ENTRY(nsIMessageSender) 4297 NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentFrameMessageManager) 4298 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 4299 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 4300 4301 NS_IMPL_ADDREF_INHERITED(BrowserChildMessageManager, DOMEventTargetHelper) 4302 NS_IMPL_RELEASE_INHERITED(BrowserChildMessageManager, DOMEventTargetHelper) 4303 4304 JSObject* BrowserChildMessageManager::WrapObject( 4305 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { 4306 return ContentFrameMessageManager_Binding::Wrap(aCx, this, aGivenProto); 4307 } 4308 4309 void BrowserChildMessageManager::MarkForCC() { 4310 if (mBrowserChild) { 4311 mBrowserChild->MarkScopesForCC(); 4312 } 4313 EventListenerManager* elm = GetExistingListenerManager(); 4314 if (elm) { 4315 elm->MarkForCC(); 4316 } 4317 MessageManagerGlobal::MarkForCC(); 4318 } 4319 4320 Nullable<WindowProxyHolder> BrowserChildMessageManager::GetContent( 4321 ErrorResult& aError) { 4322 nsCOMPtr<nsIDocShell> docShell = GetDocShell(aError); 4323 if (!docShell) { 4324 return nullptr; 4325 } 4326 return WindowProxyHolder(docShell->GetBrowsingContext()); 4327 } 4328 4329 already_AddRefed<nsIDocShell> BrowserChildMessageManager::GetDocShell( 4330 ErrorResult& aError) { 4331 if (!mBrowserChild) { 4332 aError.Throw(NS_ERROR_NULL_POINTER); 4333 return nullptr; 4334 } 4335 nsCOMPtr<nsIDocShell> window = 4336 do_GetInterface(mBrowserChild->WebNavigation()); 4337 return window.forget(); 4338 } 4339 4340 already_AddRefed<nsIEventTarget> 4341 BrowserChildMessageManager::GetTabEventTarget() { 4342 return do_AddRef(GetMainThreadSerialEventTarget()); 4343 } 4344 4345 nsresult BrowserChildMessageManager::Dispatch( 4346 already_AddRefed<nsIRunnable>&& aRunnable) const { 4347 return SchedulerGroup::Dispatch(std::move(aRunnable)); 4348 }