tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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(&current);
   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 }