Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/ipc/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 147 kB image not shown  

Quelle  BrowserParent.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "base/basictypes.h"

#include "BrowserParent.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/EventForwards.h"

#ifdef ACCESSIBILITY
#  include "mozilla/a11y/DocAccessibleParent.h"
#  include "mozilla/a11y/Platform.h"
#  include "nsAccessibilityService.h"
#endif
#include "mozilla/Components.h"
#include "mozilla/dom/BrowserHost.h"
#include "mozilla/dom/BrowserSessionStore.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/CancelContentJSOptionsBinding.h"
#include "mozilla/dom/ChromeMessageSender.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentProcessManager.h"
#include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/DataTransferItemList.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/indexedDB/ActorsParent.h"
#include "mozilla/dom/PaymentRequestParent.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/dom/BrowserBridgeParent.h"
#include "mozilla/dom/RemoteDragStartData.h"
#include "mozilla/dom/RemoteWebProgressRequest.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/SessionStoreParent.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/AsyncDragMetrics.h"
#include "mozilla/layers/InputAPZContext.h"
#include "mozilla/layout/RemoteLayerTreeOwner.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Maybe.h"
#include "mozilla/MiscEvents.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/NativeKeyBindingsType.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/net/CookieJarSettings.h"
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/ProcessHangMonitor.h"
#include "mozilla/RecursiveMutex.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/TextEvents.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "nsCOMPtr.h"
#include "nsContentPermissionHelper.h"
#include "nsContentUtils.h"
#include "nsDebug.h"
#include "nsFocusManager.h"
#include "nsFrameLoader.h"
#include "nsFrameLoaderOwner.h"
#include "nsFrameManager.h"
#include "nsIBaseWindow.h"
#include "nsIBrowser.h"
#include "nsIBrowserController.h"
#include "nsIContent.h"
#include "nsICookieJarSettings.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeOwner.h"
#include "nsImportModule.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadInfo.h"
#include "nsIPromptFactory.h"
#include "nsIURI.h"
#include "nsIWebBrowserChrome.h"
#include "nsIWebProtocolHandlerRegistrar.h"
#include "nsIWindowWatcher.h"
#include "nsIXPConnect.h"
#include "nsIXULBrowserWindow.h"
#include "nsIAppWindow.h"
#include "nsLayoutUtils.h"
#include "nsQueryActor.h"
#include "nsSHistory.h"
#include "nsViewManager.h"
#include "nsVariant.h"
#include "nsIWidget.h"
#include "nsNetUtil.h"
#ifndef XP_WIN
#  include "nsJARProtocolHandler.h"
#endif
#include "nsPIDOMWindow.h"
#include "nsPrintfCString.h"
#include "nsQueryObject.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "PermissionMessageUtils.h"
#include "StructuredCloneData.h"
#include "ColorPickerParent.h"
#include "FilePickerParent.h"
#include "BrowserChild.h"
#include "nsNetCID.h"
#include "nsIAuthInformation.h"
#include "nsIAuthPromptCallback.h"
#include "nsAuthInformationHolder.h"
#include "nsICancelable.h"
#include "gfxUtils.h"
#include "nsILoginManagerAuthPrompter.h"
#include "nsPIWindowRoot.h"
#include "nsReadableUtils.h"
#include "nsIAuthPrompt2.h"
#include "gfxDrawable.h"
#include "ImageOps.h"
#include "UnitTransforms.h"
#include <algorithm>
#include "mozilla/NullPrincipal.h"
#include "mozilla/WebBrowserPersistDocumentParent.h"
#include "ProcessPriorityManager.h"
#include "nsString.h"
#include "IHistory.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/ProfilerLabels.h"
#include "MMPrinter.h"
#include "mozilla/dom/CrashReport.h"
#include "nsISecureBrowserUI.h"
#include "nsIXULRuntime.h"
#include "VsyncSource.h"
#include "nsSubDocumentFrame.h"

#ifdef XP_WIN
#  include "FxRWindowManager.h"
#endif

#if defined(XP_WIN) && defined(ACCESSIBILITY)
#  include "mozilla/a11y/AccessibleWrap.h"
#  include "mozilla/a11y/Compatibility.h"
#  include "mozilla/a11y/nsWinUtils.h"
#endif

#ifdef MOZ_GECKOVIEW_HISTORY
#  include "GeckoViewHistory.h"
#endif

#if defined(MOZ_WIDGET_ANDROID)
#  include "mozilla/widget/nsWindow.h"
#endif  // defined(MOZ_WIDGET_ANDROID)

using namespace mozilla::dom;
using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::layout;
using namespace mozilla::services;
using namespace mozilla::widget;
using namespace mozilla::gfx;

using mozilla::LazyLogModule;

extern mozilla::LazyLogModule gSHIPBFCacheLog;

LazyLogModule gBrowserFocusLog("BrowserFocus");

#define LOGBROWSERFOCUS(args) \
  MOZ_LOG(gBrowserFocusLog, mozilla::LogLevel::Debug, args)

/* static */
BrowserParent* BrowserParent::sFocus = nullptr;
/* static */
BrowserParent* BrowserParent::sTopLevelWebFocus = nullptr;
/* static */
BrowserParent* BrowserParent::sLastMouseRemoteTarget = nullptr;

// The flags passed by the webProgress notifications are 16 bits shifted
// from the ones registered by webProgressListeners.
#define NOTIFY_FLAG_SHIFT 16

namespace mozilla {

/**
 * Store data of a keypress event which is requesting to handled it in a remote
 * process or some remote processes.
 */

class RequestingAccessKeyEventData {
 public:
  RequestingAccessKeyEventData() = delete;

  static void OnBrowserParentCreated() {
    MOZ_ASSERT(sBrowserParentCount <= INT32_MAX);
    sBrowserParentCount++;
  }
  static void OnBrowserParentDestroyed() {
    MOZ_ASSERT(sBrowserParentCount > 0);
    sBrowserParentCount--;
    // To avoid memory leak, we need to reset sData when the last BrowserParent
    // is destroyed.
    if (!sBrowserParentCount) {
      Clear();
    }
  }

  static void Set(const WidgetKeyboardEvent& aKeyPressEvent) {
    MOZ_ASSERT(aKeyPressEvent.mMessage == eKeyPress);
    MOZ_ASSERT(sBrowserParentCount > 0);
    sData =
        Some(Data{aKeyPressEvent.mAlternativeCharCodes, aKeyPressEvent.mKeyCode,
                  aKeyPressEvent.mCharCode, aKeyPressEvent.mKeyNameIndex,
                  aKeyPressEvent.mCodeNameIndex, aKeyPressEvent.mKeyValue,
                  aKeyPressEvent.mModifiers});
  }

  static void Clear() { sData.reset(); }

  [[nodiscard]] static bool Equals(const WidgetKeyboardEvent& aKeyPressEvent) {
    MOZ_ASSERT(sBrowserParentCount > 0);
    return sData.isSome() && sData->Equals(aKeyPressEvent);
  }

  [[nodiscard]] static bool IsSet() {
    MOZ_ASSERT(sBrowserParentCount > 0);
    return sData.isSome();
  }

 private:
  struct Data {
    [[nodiscard]] bool Equals(const WidgetKeyboardEvent& aKeyPressEvent) {
      return mKeyCode == aKeyPressEvent.mKeyCode &&
             mCharCode == aKeyPressEvent.mCharCode &&
             mKeyNameIndex == aKeyPressEvent.mKeyNameIndex &&
             mCodeNameIndex == aKeyPressEvent.mCodeNameIndex &&
             mKeyValue == aKeyPressEvent.mKeyValue &&
             mModifiers == aKeyPressEvent.mModifiers &&
             mAlternativeCharCodes == aKeyPressEvent.mAlternativeCharCodes;
    }

    CopyableTArray<AlternativeCharCode> mAlternativeCharCodes;
    uint32_t mKeyCode;
    uint32_t mCharCode;
    KeyNameIndex mKeyNameIndex;
    CodeNameIndex mCodeNameIndex;
    nsString mKeyValue;
    Modifiers mModifiers;
  };
  static Maybe<Data> sData;
  static int32_t sBrowserParentCount;
};
int32_t RequestingAccessKeyEventData::sBrowserParentCount = 0;
MOZ_RUNINIT Maybe<RequestingAccessKeyEventData::Data>
    RequestingAccessKeyEventData::sData;

namespace dom {

BrowserParent::LayerToBrowserParentTable*
    BrowserParent::sLayerToBrowserParentTable = nullptr;

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserParent)
  NS_INTERFACE_MAP_ENTRY_CONCRETE(BrowserParent)
  NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTION_CLASS(BrowserParent)

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowserParent)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserDOMWindow)
  tmp->UnlinkManager();
  NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowserParent)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserDOMWindow)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(Manager())
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowserParent)
NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowserParent)

BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId,
                             const TabContext& aContext,
                             CanonicalBrowsingContext* aBrowsingContext,
                             uint32_t aChromeFlags)
    : TabContext(aContext),
      mTabId(aTabId),
      mBrowsingContext(aBrowsingContext),
      mFrameElement(nullptr),
      mBrowserDOMWindow(nullptr),
      mFrameLoader(nullptr),
      mChromeFlags(aChromeFlags),
      mBrowserBridgeParent(nullptr),
      mBrowserHost(nullptr),
      mContentCache(*this),
      mRect(0, 0, 0, 0),
      mDimensions(0, 0),
      mDPI(0),
      mRounding(0),
      mDefaultScale(0),
      mUpdatedDimensions(false),
      mSizeMode(nsSizeMode_Normal),
      mCreatingWindow(false),
      mMarkedDestroying(false),
      mIsDestroyed(false),
      mRemoteTargetSetsCursor(false),
      mIsPreservingLayers(false),
      mRenderLayers(true),
      mPriorityHint(false),
      mHasLayers(false),
      mHasPresented(false),
      mIsReadyToHandleInputEvents(false),
      mIsMouseEnterIntoWidgetEventSuppressed(false),
      mLockedNativePointer(false),
      mShowingTooltip(false) {
  MOZ_ASSERT(aManager);

  // We access `Manager()` when updating priorities later in this constructor,
  // so need to initialize it before IPC does.
  SetManager(aManager);

  // Add a KeepAlive for this BrowserParent upon creation.
  mContentParentKeepAlive =
      aManager->TryAddKeepAlive(aBrowsingContext->BrowserId());

  RequestingAccessKeyEventData::OnBrowserParentCreated();

  // Make sure to compute our process priority if needed before the block of
  // code below. This makes sure the block below prioritizes our process if
  // needed.
  if (aBrowsingContext->IsTop()) {
    RecomputeProcessPriority();
  }

  // Reflect the BC tree's activeness state on this new BrowserParent. This
  // ensures that the process will be correctly prioritized based on the
  // BrowsingContext's current priority after a navigation.
  // If the BC is not active, we still call `BrowserPriorityChanged` to ensure
  // the priority is lowered if the BrowsingContext is inactive, but the process
  // still has FOREGROUND priority from when it was launched.
  ProcessPriorityManager::BrowserPriorityChanged(
      this, aBrowsingContext->Top()->IsPriorityActive());
}

BrowserParent::~BrowserParent() {
  RequestingAccessKeyEventData::OnBrowserParentDestroyed();
}

/* static */
BrowserParent* BrowserParent::GetFocused() { return sFocus; }

/* static */
BrowserParent* BrowserParent::GetLastMouseRemoteTarget() {
  return sLastMouseRemoteTarget;
}

/*static*/
BrowserParent* BrowserParent::GetFrom(nsFrameLoader* aFrameLoader) {
  if (!aFrameLoader) {
    return nullptr;
  }
  return aFrameLoader->GetBrowserParent();
}

/*static*/
BrowserParent* BrowserParent::GetFrom(PBrowserParent* aBrowserParent) {
  return static_cast<BrowserParent*>(aBrowserParent);
}

/*static*/
BrowserParent* BrowserParent::GetFrom(nsIContent* aContent) {
  RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(aContent);
  if (!loaderOwner) {
    return nullptr;
  }
  RefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
  return GetFrom(frameLoader);
}

/* static */
BrowserParent* BrowserParent::GetBrowserParentFromLayersId(
    layers::LayersId aLayersId) {
  if (!sLayerToBrowserParentTable) {
    return nullptr;
  }
  return sLayerToBrowserParentTable->Get(uint64_t(aLayersId));
}

/*static*/
TabId BrowserParent::GetTabIdFrom(nsIDocShell* docShell) {
  nsCOMPtr<nsIBrowserChild> browserChild(BrowserChild::GetFrom(docShell));
  if (browserChild) {
    return static_cast<BrowserChild*>(browserChild.get())->GetTabId();
  }
  return TabId(0);
}

ContentParent* BrowserParent::Manager() const {
  return static_cast<ContentParent*>(PBrowserParent::Manager());
}

void BrowserParent::AddBrowserParentToTable(layers::LayersId aLayersId,
                                            BrowserParent* aBrowserParent) {
  if (!sLayerToBrowserParentTable) {
    sLayerToBrowserParentTable = new LayerToBrowserParentTable();
  }
  sLayerToBrowserParentTable->InsertOrUpdate(uint64_t(aLayersId),
                                             aBrowserParent);
}

void BrowserParent::RemoveBrowserParentFromTable(layers::LayersId aLayersId) {
  if (!sLayerToBrowserParentTable) {
    return;
  }
  sLayerToBrowserParentTable->Remove(uint64_t(aLayersId));
  if (sLayerToBrowserParentTable->Count() == 0) {
    delete sLayerToBrowserParentTable;
    sLayerToBrowserParentTable = nullptr;
  }
}

already_AddRefed<nsILoadContext> BrowserParent::GetLoadContext() {
  return do_AddRef(mBrowsingContext);
}

/**
 * Will return nullptr if there is no outer window available for the
 * document hosting the owner element of this BrowserParent. Also will return
 * nullptr if that outer window is in the process of closing.
 */

already_AddRefed<nsPIDOMWindowOuter> BrowserParent::GetParentWindowOuter() {
  nsCOMPtr<nsIContent> frame = GetOwnerElement();
  if (!frame) {
    return nullptr;
  }

  nsCOMPtr<nsPIDOMWindowOuter> parent = frame->OwnerDoc()->GetWindow();
  if (!parent || parent->Closed()) {
    return nullptr;
  }

  return parent.forget();
}

already_AddRefed<nsIWidget> BrowserParent::GetTopLevelWidget() {
  if (RefPtr<Element> element = mFrameElement) {
    if (PresShell* presShell = element->OwnerDoc()->GetPresShell()) {
      return do_AddRef(presShell->GetViewManager()->GetRootWidget());
    }
  }
  return nullptr;
}

already_AddRefed<nsIWidget> BrowserParent::GetTextInputHandlingWidget() const {
  if (!mFrameElement) {
    return nullptr;
  }
  PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
  if (!presShell) {
    return nullptr;
  }
  nsPresContext* presContext = presShell->GetPresContext();
  if (!presContext) {
    return nullptr;
  }
  nsCOMPtr<nsIWidget> widget = presContext->GetTextInputHandlingWidget();
  return widget.forget();
}

already_AddRefed<nsIWidget> BrowserParent::GetWidget() const {
  if (!mFrameElement) {
    return nullptr;
  }
  nsCOMPtr<nsIWidget> widget = nsContentUtils::WidgetForContent(mFrameElement);
  if (!widget) {
    widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc());
  }
  return widget.forget();
}

already_AddRefed<nsIWidget> BrowserParent::GetDocWidget() const {
  if (!mFrameElement) {
    return nullptr;
  }
  return do_AddRef(
      nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc()));
}

nsIXULBrowserWindow* BrowserParent::GetXULBrowserWindow() {
  if (!mFrameElement) {
    return nullptr;
  }

  nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
  if (!docShell) {
    return nullptr;
  }

  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
  docShell->GetTreeOwner(getter_AddRefs(treeOwner));
  if (!treeOwner) {
    return nullptr;
  }

  nsCOMPtr<nsIAppWindow> window = do_GetInterface(treeOwner);
  if (!window) {
    return nullptr;
  }

  nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow;
  window->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow));
  return xulBrowserWindow;
}

uint32_t BrowserParent::GetMaxTouchPoints(Element* aElement) {
  if (!aElement) {
    return 0;
  }

  if (StaticPrefs::dom_maxtouchpoints_testing_value() >= 0) {
    return StaticPrefs::dom_maxtouchpoints_testing_value();
  }

  nsIWidget* widget = nsContentUtils::WidgetForDocument(aElement->OwnerDoc());
  return widget ? widget->GetMaxTouchPoints() : 0;
}

a11y::DocAccessibleParent* BrowserParent::GetTopLevelDocAccessible() const {
#ifdef ACCESSIBILITY
  // XXX Consider managing non top level PDocAccessibles with their parent
  // document accessible.
  const ManagedContainer<PDocAccessibleParent>& docs =
      ManagedPDocAccessibleParent();
  for (auto* key : docs) {
    auto* doc = static_cast<a11y::DocAccessibleParent*>(key);
    // We want the document for this BrowserParent even if it's for an
    // embedded out-of-process iframe. Therefore, we use
    // IsTopLevelInContentProcess. In contrast, using IsToplevel would only
    // include documents that aren't embedded; e.g. tab documents.
    if (doc->IsTopLevelInContentProcess() && !doc->IsShutdown()) {
      return doc;
    }
  }
#endif
  return nullptr;
}

LayersId BrowserParent::GetLayersId() const {
  if (!mRemoteLayerTreeOwner.IsInitialized()) {
    return LayersId{};
  }
  return mRemoteLayerTreeOwner.GetLayersId();
}

BrowserBridgeParent* BrowserParent::GetBrowserBridgeParent() const {
  return mBrowserBridgeParent;
}

BrowserHost* BrowserParent::GetBrowserHost() const { return mBrowserHost; }

ParentShowInfo BrowserParent::GetShowInfo() {
  TryCacheDPIAndScale();
  if (mFrameElement) {
    nsAutoString name;
    mFrameElement->GetAttr(nsGkAtoms::name, name);
    bool isTransparent =
        nsContentUtils::IsChromeDoc(mFrameElement->OwnerDoc()) &&
        mFrameElement->HasAttr(nsGkAtoms::transparent);
    return ParentShowInfo(name, false, isTransparent, mDPI, mRounding,
                          mDefaultScale.scale);
  }

  return ParentShowInfo(u""_ns, falsefalse, mDPI, mRounding,
                        mDefaultScale.scale);
}

already_AddRefed<nsIPrincipal> BrowserParent::GetContentPrincipal() const {
  nsCOMPtr<nsIBrowser> browser =
      mFrameElement ? mFrameElement->AsBrowser() : nullptr;
  NS_ENSURE_TRUE(browser, nullptr);

  RefPtr<nsIPrincipal> principal;

  nsresult rv;
  rv = browser->GetContentPrincipal(getter_AddRefs(principal));
  NS_ENSURE_SUCCESS(rv, nullptr);

  return principal.forget();
}

void BrowserParent::SetOwnerElement(Element* aElement) {
  // If we held previous content then unregister for its events.
  RemoveWindowListeners();

  // If we change top-level documents then we need to change our
  // registration with them.
  RefPtr<nsPIWindowRoot> curTopLevelWin, newTopLevelWin;
  if (mFrameElement) {
    curTopLevelWin = nsContentUtils::GetWindowRoot(mFrameElement->OwnerDoc());
  }
  if (aElement) {
    newTopLevelWin = nsContentUtils::GetWindowRoot(aElement->OwnerDoc());
  }
  bool isSameTopLevelWin = curTopLevelWin == newTopLevelWin;
  if (mBrowserHost && curTopLevelWin && !isSameTopLevelWin) {
    curTopLevelWin->RemoveBrowser(mBrowserHost);
  }

  // Update to the new content, and register to listen for events from it.
  mFrameElement = aElement;

  if (mBrowserHost && newTopLevelWin && !isSameTopLevelWin) {
    newTopLevelWin->AddBrowser(mBrowserHost);
  }

#if defined(XP_WIN) && defined(ACCESSIBILITY)
  if (!mIsDestroyed) {
    uintptr_t newWindowHandle = 0;
    if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
      newWindowHandle =
          reinterpret_cast<uintptr_t>(widget->GetNativeData(NS_NATIVE_WINDOW));
    }
    Unused << SendUpdateNativeWindowHandle(newWindowHandle);
    a11y::DocAccessibleParent* doc = GetTopLevelDocAccessible();
    if (doc) {
      HWND hWnd = reinterpret_cast<HWND>(doc->GetEmulatedWindowHandle());
      if (hWnd) {
        HWND parentHwnd = reinterpret_cast<HWND>(newWindowHandle);
        if (parentHwnd != ::GetParent(hWnd)) {
          ::SetParent(hWnd, parentHwnd);
        }
      }
    }
  }
#endif

  AddWindowListeners();

  // The DPI depends on our frame element's widget, so invalidate now in case
  // we've tried to cache it already.
  mDPI = -1;
  TryCacheDPIAndScale();

  if (mRemoteLayerTreeOwner.IsInitialized()) {
    mRemoteLayerTreeOwner.OwnerContentChanged();
  }

  // Set our BrowsingContext's embedder if we're not embedded within a
  // BrowserBridgeParent.
  if (!GetBrowserBridgeParent() && mBrowsingContext && mFrameElement) {
    mBrowsingContext->SetEmbedderElement(mFrameElement);
  }

  UpdateVsyncParentVsyncDispatcher();

  VisitChildren([aElement](BrowserBridgeParent* aBrowser) {
    if (auto* browserParent = aBrowser->GetBrowserParent()) {
      browserParent->SetOwnerElement(aElement);
    }
  });
}

void BrowserParent::CacheFrameLoader(nsFrameLoader* aFrameLoader) {
  mFrameLoader = aFrameLoader;
}

void BrowserParent::AddWindowListeners() {
  if (mFrameElement) {
    if (nsCOMPtr<nsPIDOMWindowOuter> window =
            mFrameElement->OwnerDoc()->GetWindow()) {
      nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
      if (eventTarget) {
        eventTarget->AddEventListener(u"MozUpdateWindowPos"_ns, thisfalse,
                                      false);
        eventTarget->AddEventListener(u"fullscreenchange"_ns, thisfalse,
                                      false);
      }
    }
  }
}

void BrowserParent::RemoveWindowListeners() {
  if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
    nsCOMPtr<nsPIDOMWindowOuter> window =
        mFrameElement->OwnerDoc()->GetWindow();
    nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
    if (eventTarget) {
      eventTarget->RemoveEventListener(u"MozUpdateWindowPos"_ns, thisfalse);
      eventTarget->RemoveEventListener(u"fullscreenchange"_ns, thisfalse);
    }
  }
}

void BrowserParent::Deactivated() {
  if (mShowingTooltip) {
    // Reuse the normal tooltip hiding method.
    mozilla::Unused << RecvHideTooltip();
  }
  UnlockNativePointer();
  UnsetTopLevelWebFocus(this);
  UnsetLastMouseRemoteTarget(this);
  PointerLockManager::ReleaseLockedRemoteTarget(this);
  PointerEventHandler::ReleasePointerCaptureRemoteTarget(this);
  PresShell::ReleaseCapturingRemoteTarget(this);
  ProcessPriorityManager::BrowserPriorityChanged(this/* aPriority = */ false);
}

void BrowserParent::Destroy() {
  // Aggressively release the window to avoid leaking the world in shutdown
  // corner cases.
  mBrowserDOMWindow = nullptr;

  if (mIsDestroyed) {
    return;
  }

  Deactivated();

  RemoveWindowListeners();

#ifdef ACCESSIBILITY
  if (a11y::DocAccessibleParent* tabDoc = GetTopLevelDocAccessible()) {
#  if defined(ANDROID)
    MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
#  endif
    tabDoc->Destroy();
  }
#endif

  // If this fails, it's most likely due to a content-process crash, and
  // auto-cleanup will kick in.  Otherwise, the child side will destroy itself
  // and send back __delete__().
  (void)SendDestroy();
  mIsDestroyed = true;

#if !defined(MOZ_WIDGET_ANDROID)
  // We're beginning to destroy this BrowserParent. Immediately drop the
  // keepalive. This can start the shutdown timer, however the ShutDown message
  // will wait for the BrowserParent to be fully destroyed.
  //
  // NOTE: We intentionally skip this step on Android, keeping the KeepAlive
  // active until the BrowserParent is fully destroyed:
  // 1. Android has a fixed upper bound on the number of content processes, so
  //    we prefer to re-use them whenever possible (as opposed to letting an
  //    old process wind down while we launch a new one). This restriction will
  //    be relaxed after bug 1565196.
  // 2. GeckoView always hard-kills content processes (and if it does not,
  //    Android itself will), so we don't concern ourselves with the ForceKill
  //    timer either.
  mContentParentKeepAlive = nullptr;
#endif

  // This `AddKeepAlive` will be cleared if `mMarkedDestroying` is set in
  // `ActorDestroy`. Out of caution, we don't add the `KeepAlive` if our IPC
  // actor has somehow already been destroyed, as that would mean `ActorDestroy`
  // won't be called.
  if (CanRecv()) {
    mBrowsingContext->Group()->AddKeepAlive();
  }

  mMarkedDestroying = true;
}

mozilla::ipc::IPCResult BrowserParent::RecvDidUnsuppressPainting() {
  if (!mFrameElement) {
    return IPC_OK();
  }
  nsSubDocumentFrame* subdocFrame =
      do_QueryFrame(mFrameElement->GetPrimaryFrame());
  if (subdocFrame && subdocFrame->HasRetainedPaintData()) {
    subdocFrame->ClearRetainedPaintData();
  }
  return IPC_OK();
}

mozilla::ipc::IPCResult BrowserParent::RecvEnsureLayersConnected(
    CompositorOptions* aCompositorOptions) {
  if (mRemoteLayerTreeOwner.IsInitialized()) {
    mRemoteLayerTreeOwner.EnsureLayersConnected(aCompositorOptions);
  }
  return IPC_OK();
}

void BrowserParent::ActorDestroy(ActorDestroyReason why) {
  // Need to close undeleted ContentPermissionRequestParents before tab is
  // closed.
  // FIXME: Why is PContentPermissionRequest not managed by PBrowser?
  nsTArray<PContentPermissionRequestParent*> parentArray =
      nsContentPermissionUtils::GetContentPermissionRequestParentById(mTabId);
  for (auto& permissionRequestParent : parentArray) {
    Unused << PContentPermissionRequestParent::Send__delete__(
        permissionRequestParent);
  }

  // Ensure the ContentParentKeepAlive has been cleared when the actor is
  // destroyed, and re-check if it's time to send the ShutDown message.
  mContentParentKeepAlive = nullptr;
  Manager()->MaybeBeginShutDown();

  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
  if (cpm) {
    cpm->UnregisterRemoteFrame(mTabId);
  }

  if (mRemoteLayerTreeOwner.IsInitialized()) {
    auto layersId = mRemoteLayerTreeOwner.GetLayersId();
    if (mFrameElement) {
      nsSubDocumentFrame* f = do_QueryFrame(mFrameElement->GetPrimaryFrame());
      if (f && f->HasRetainedPaintData() &&
          f->GetRemotePaintData().mLayersId == layersId) {
        f->ClearRetainedPaintData();
      }
    }

    // It's important to unmap layers after the remote browser has been
    // destroyed, otherwise it may still send messages to the compositor which
    // will reject them, causing assertions.
    RemoveBrowserParentFromTable(layersId);
    mRemoteLayerTreeOwner.Destroy();
  }

  // Even though BrowserParent::Destroy calls this, we need to do it here too in
  // case of a crash.
  Deactivated();

  if (why == AbnormalShutdown) {
    // dom_reporting_header must also be enabled for the report to be sent.
    if (StaticPrefs::dom_reporting_crash_enabled()) {
      nsCOMPtr<nsIPrincipal> principal = GetContentPrincipal();

      if (principal) {
        nsAutoCString crash_reason;
        CrashReporter::GetAnnotation(OtherPid(),
                                     CrashReporter::Annotation::MozCrashReason,
                                     crash_reason);
        // FIXME(arenevier): Find a less fragile way to identify that a crash
        // was caused by OOM
        bool is_oom = false;
        if (crash_reason == "OOM" || crash_reason == "OOM!" ||
            StringBeginsWith(crash_reason, "[unhandlable oom]"_ns) ||
            StringBeginsWith(crash_reason, "Unhandlable OOM"_ns)) {
          is_oom = true;
        }

        CrashReport::Deliver(principal, is_oom);
      }
    }
  }

  // If we were shutting down normally, we held a reference to our
  // BrowsingContextGroup in `BrowserParent::Destroy`. Clear that reference
  // here.
  if (mMarkedDestroying) {
    mBrowsingContext->Group()->RemoveKeepAlive();
  }

  // Tell our embedder that the tab is now going away unless we're an
  // out-of-process iframe.
  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
  if (frameLoader) {
    if (mBrowsingContext->IsTop()) {
      // If this is a top-level BrowsingContext, tell the frameloader it's time
      // to go away. Otherwise, this is a subframe crash, and we can keep the
      // frameloader around.
      frameLoader->DestroyComplete();
    }

    // If this was a crash, tell our nsFrameLoader to fire crash events.
    if (why == AbnormalShutdown) {
      frameLoader->MaybeNotifyCrashed(mBrowsingContext, Manager()->ChildID(),
                                      GetIPCChannel());
    } else if (why == ManagedEndpointDropped) {
      // If we instead failed due to a constructor error, don't include process
      // information, as the process did not crash.
      frameLoader->MaybeNotifyCrashed(mBrowsingContext, ContentParentId{},
                                      nullptr);
    }
  }

  mFrameLoader = nullptr;

  // If we were destroyed due to our ManagedEndpoints being dropped, make a
  // point of showing the subframe crashed UI. We don't fire the full
  // `MaybeNotifyCrashed` codepath, as the entire process hasn't crashed on us,
  // and it may confuse the frontend.
  mBrowsingContext->BrowserParentDestroyed(
      this, why == AbnormalShutdown || why == ManagedEndpointDropped);
}

mozilla::ipc::IPCResult BrowserParent::RecvMoveFocus(
    const bool& aForward, const bool& aForDocumentNavigation) {
  LOGBROWSERFOCUS(("RecvMoveFocus %p, aForward: %d, aForDocumentNavigation: %d",
                   this, aForward, aForDocumentNavigation));
  BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent();
  if (bridgeParent) {
    mozilla::Unused << bridgeParent->SendMoveFocus(aForward,
                                                   aForDocumentNavigation);
    return IPC_OK();
  }

  RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
  if (fm) {
    RefPtr<Element> dummy;

    uint32_t type =
        aForward
            ? (aForDocumentNavigation
                   ? static_cast<uint32_t>(
                         nsIFocusManager::MOVEFOCUS_FORWARDDOC)
                   : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD))
            : (aForDocumentNavigation
                   ? static_cast<uint32_t>(
                         nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
                   : static_cast<uint32_t>(
                         nsIFocusManager::MOVEFOCUS_BACKWARD));
    fm->MoveFocus(nullptr, mFrameElement, type, nsIFocusManager::FLAG_BYKEY,
                  getter_AddRefs(dummy));
  }
  return IPC_OK();
}

mozilla::ipc::IPCResult BrowserParent::RecvDropLinks(
    nsTArray<nsString>&& aLinks) {
  nsCOMPtr<nsIBrowser> browser =
      mFrameElement ? mFrameElement->AsBrowser() : nullptr;
  if (browser) {
    // Verify that links have not been modified by the child. If links have
    // not been modified then it's safe to load those links using the
    // SystemPrincipal. If they have been modified by web content, then
    // we use a NullPrincipal which still allows to load web links.
    bool loadUsingSystemPrincipal = true;
    if (aLinks.Length() != mVerifyDropLinks.Length()) {
      loadUsingSystemPrincipal = false;
    }
    for (uint32_t i = 0; i < aLinks.Length(); i++) {
      if (loadUsingSystemPrincipal) {
        if (!aLinks[i].Equals(mVerifyDropLinks[i])) {
          loadUsingSystemPrincipal = false;
        }
      }
    }
    mVerifyDropLinks.Clear();
    nsCOMPtr<nsIPrincipal> triggeringPrincipal;
    if (loadUsingSystemPrincipal) {
      triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
    } else {
      triggeringPrincipal = NullPrincipal::CreateWithoutOriginAttributes();
    }
    browser->DropLinks(aLinks, triggeringPrincipal);
  }
  return IPC_OK();
}

bool BrowserParent::SendLoadRemoteScript(const nsAString& aURL,
                                         const bool& aRunInGlobalScope) {
  if (mCreatingWindow) {
    mDelayedFrameScripts.AppendElement(
        FrameScriptInfo(nsString(aURL), aRunInGlobalScope));
    return true;
  }

  MOZ_ASSERT(mDelayedFrameScripts.IsEmpty());
  return PBrowserParent::SendLoadRemoteScript(aURL, aRunInGlobalScope);
}

void BrowserParent::LoadURL(nsDocShellLoadState* aLoadState) {
  MOZ_ASSERT(aLoadState);
  MOZ_ASSERT(aLoadState->URI());
  if (mIsDestroyed) {
    return;
  }

  if (mCreatingWindow) {
    // Don't send the message if the child wants to load its own URL.
    return;
  }

  Unused << SendLoadURL(WrapNotNull(aLoadState), GetShowInfo());
}

void BrowserParent::ResumeLoad(uint64_t aPendingSwitchID) {
  MOZ_ASSERT(aPendingSwitchID != 0);

  if (NS_WARN_IF(mIsDestroyed)) {
    return;
  }

  Unused << SendResumeLoad(aPendingSwitchID, GetShowInfo());
}

void BrowserParent::InitRendering() {
  if (mRemoteLayerTreeOwner.IsInitialized()) {
    return;
  }
  mRemoteLayerTreeOwner.Initialize(this);

  layers::LayersId layersId = mRemoteLayerTreeOwner.GetLayersId();
  AddBrowserParentToTable(layersId, this);

  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
  if (frameLoader) {
    nsIFrame* frame = frameLoader->GetPrimaryFrameOfOwningContent();
    if (frame) {
      frame->InvalidateFrame();
    }
  }

  TextureFactoryIdentifier textureFactoryIdentifier;
  mRemoteLayerTreeOwner.GetTextureFactoryIdentifier(&textureFactoryIdentifier);
  Unused << SendInitRendering(textureFactoryIdentifier, layersId,
                              mRemoteLayerTreeOwner.GetCompositorOptions(),
                              mRemoteLayerTreeOwner.IsLayersConnected());

  RefPtr<nsIWidget> widget = GetTopLevelWidget();
  if (widget) {
    Unused << SendSafeAreaInsetsChanged(widget->GetSafeAreaInsets());
  }

#if defined(MOZ_WIDGET_ANDROID)
  MOZ_ASSERT(widget);

  if (GetBrowsingContext()->IsTopContent()) {
    Unused << SendDynamicToolbarMaxHeightChanged(
        widget->GetDynamicToolbarMaxHeight());
  }
#endif
}

bool BrowserParent::AttachWindowRenderer() {
  return mRemoteLayerTreeOwner.AttachWindowRenderer();
}

void BrowserParent::MaybeShowFrame() {
  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
  if (!frameLoader) {
    return;
  }
  frameLoader->MaybeShowFrame();
}

bool BrowserParent::Show(const OwnerShowInfo& aOwnerInfo) {
  mDimensions = aOwnerInfo.size();
  if (mIsDestroyed) {
    return false;
  }

  MOZ_ASSERT(mRemoteLayerTreeOwner.IsInitialized());
  if (!mRemoteLayerTreeOwner.AttachWindowRenderer()) {
    return false;
  }

  mSizeMode = aOwnerInfo.sizeMode();
  Unused << SendShow(GetShowInfo(), aOwnerInfo);
  return true;
}

mozilla::ipc::IPCResult BrowserParent::RecvSetDimensions(
    mozilla::DimensionRequest aRequest, const double& aScale) {
  NS_ENSURE_TRUE(mFrameElement, IPC_OK());
  nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
  NS_ENSURE_TRUE(docShell, IPC_OK());
  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
  docShell->GetTreeOwner(getter_AddRefs(treeOwner));
  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner);
  NS_ENSURE_TRUE(treeOwnerAsWin, IPC_OK());

  // `BrowserChild` only sends the values to actually be changed, see more
  // details in `BrowserChild::SetDimensions()`.
  // Note that `BrowserChild::SetDimensions()` may be called before receiving
  // our `SendUIResolutionChanged()` call.  Therefore, if given each coordinate
  // shouldn't be ignored, we need to recompute it if DPI has been changed.
  // And also note that don't use `mDefaultScale.scale` here since it may be
  // different from the result of `GetWidgetCSSToDeviceScale()`.
  // NOTE(emilio): We use GetWidgetCSSToDeviceScale() because the old scale is a
  // widget scale, and we only use the current scale to scale up/down the
  // relevant values.

  CSSToLayoutDeviceScale oldScale((float)aScale);
  CSSToLayoutDeviceScale currentScale(
      (float)treeOwnerAsWin->GetWidgetCSSToDeviceScale());

  if (oldScale != currentScale) {
    auto rescaleFunc = [&oldScale, ¤tScale](LayoutDeviceIntCoord& aVal) {
      aVal = (LayoutDeviceCoord(aVal) / oldScale * currentScale).Rounded();
    };
    aRequest.mX.apply(rescaleFunc);
    aRequest.mY.apply(rescaleFunc);
    aRequest.mWidth.apply(rescaleFunc);
    aRequest.mHeight.apply(rescaleFunc);
  }

  // treeOwner is the chrome tree owner, but we wan't the content tree owner.
  nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = do_GetInterface(treeOwner);
  NS_ENSURE_TRUE(webBrowserChrome, IPC_OK());
  webBrowserChrome->SetDimensions(std::move(aRequest));
  return IPC_OK();
}

nsresult BrowserParent::UpdatePosition() {
  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
  if (!frameLoader) {
    return NS_OK;
  }
  LayoutDeviceIntRect windowDims;
  NS_ENSURE_SUCCESS(frameLoader->GetWindowDimensions(windowDims),
                    NS_ERROR_FAILURE);
  // Avoid updating sizes here.
  windowDims.SizeTo(mRect.Size());
  UpdateDimensions(windowDims, mDimensions);
  return NS_OK;
}

void BrowserParent::NotifyPositionUpdatedForContentsInPopup() {
  if (CanonicalBrowsingContext* bc = GetBrowsingContext()) {
    bc->PreOrderWalk([](BrowsingContext* aContext) {
      if (WindowGlobalParent* windowGlobalParent =
              aContext->Canonical()->GetCurrentWindowGlobal()) {
        if (RefPtr<BrowserParent> browserParent =
                windowGlobalParent->GetBrowserParent()) {
          browserParent->UpdatePosition();
        }
      }
    });
  }
}

void BrowserParent::UpdateDimensions(const LayoutDeviceIntRect& rect,
                                     const LayoutDeviceIntSize& size) {
  if (mIsDestroyed) {
    return;
  }
  nsCOMPtr<nsIWidget> widget = GetWidget();
  if (!widget) {
    NS_WARNING("No widget found in BrowserParent::UpdateDimensions");
    return;
  }

  LayoutDeviceIntPoint clientOffset = GetClientOffset();
  LayoutDeviceIntPoint chromeOffset = !GetBrowserBridgeParent()
                                          ? -GetChildProcessOffset()
                                          : LayoutDeviceIntPoint();

  if (!mUpdatedDimensions || mDimensions != size || !mRect.IsEqualEdges(rect) ||
      clientOffset != mClientOffset || chromeOffset != mChromeOffset) {
    mUpdatedDimensions = true;
    mRect = rect;
    mDimensions = size;
    mClientOffset = clientOffset;
    mChromeOffset = chromeOffset;

    Unused << SendUpdateDimensions(GetDimensionInfo());
    UpdateNativePointerLockCenter(widget);
  }
}

DimensionInfo BrowserParent::GetDimensionInfo() {
  CSSRect unscaledRect = mRect / mDefaultScale;
  CSSSize unscaledSize = mDimensions / mDefaultScale;
  return DimensionInfo(unscaledRect, unscaledSize, mClientOffset,
                       mChromeOffset);
}

void BrowserParent::UpdateNativePointerLockCenter(nsIWidget* aWidget) {
  if (!mLockedNativePointer) {
    return;
  }
  aWidget->SetNativePointerLockCenter(
      LayoutDeviceIntRect(mChromeOffset, mDimensions).Center());
}

void BrowserParent::SizeModeChanged(const nsSizeMode& aSizeMode) {
  if (!mIsDestroyed && aSizeMode != mSizeMode) {
    mSizeMode = aSizeMode;
    Unused << SendSizeModeChanged(aSizeMode);
  }
}

#if defined(MOZ_WIDGET_ANDROID)
void BrowserParent::DynamicToolbarMaxHeightChanged(ScreenIntCoord aHeight) {
  if (!mIsDestroyed) {
    Unused << SendDynamicToolbarMaxHeightChanged(aHeight);
  }
}

void BrowserParent::DynamicToolbarOffsetChanged(ScreenIntCoord aOffset) {
  if (!mIsDestroyed) {
    Unused << SendDynamicToolbarOffsetChanged(aOffset);
  }
}

void BrowserParent::KeyboardHeightChanged(ScreenIntCoord aHeight) {
  if (!mIsDestroyed) {
    Unused << SendKeyboardHeightChanged(aHeight);
  }
}
#endif

void BrowserParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
                                    nsTArray<uint32_t>& aCharCodes) {
  if (!mIsDestroyed) {
    // Note that we don't need to mark aEvent is posted to a remote process
    // because the event may be dispatched to it as normal keyboard event.
    // Therefore, we should use local copy to send it.
    WidgetKeyboardEvent localEvent(aEvent);
    RequestingAccessKeyEventData::Set(localEvent);
    Unused << SendHandleAccessKey(localEvent, aCharCodes);
  }
}

void BrowserParent::Activate(uint64_t aActionId) {
  LOGBROWSERFOCUS(("Activate %p actionid: %" PRIu64, this, aActionId));
  if (!mIsDestroyed) {
    SetTopLevelWebFocus(this);  // Intentionally inside "if"
    Unused << SendActivate(aActionId);
  }
}

void BrowserParent::Deactivate(bool aWindowLowering, uint64_t aActionId) {
  LOGBROWSERFOCUS(("Deactivate %p actionid: %" PRIu64, this, aActionId));
  if (!aWindowLowering) {
    UnsetTopLevelWebFocus(this);  // Intentionally outside the next "if"
  }
  if (!mIsDestroyed) {
    Unused << SendDeactivate(aActionId);
  }
}

#ifdef ACCESSIBILITY
a11y::PDocAccessibleParent* BrowserParent::AllocPDocAccessibleParent(
    PDocAccessibleParent* aParent, const uint64_t&,
    const MaybeDiscardedBrowsingContext&) {
  // Reference freed in DeallocPDocAccessibleParent.
  return a11y::DocAccessibleParent::New().take();
}

bool BrowserParent::DeallocPDocAccessibleParent(PDocAccessibleParent* aParent) {
  // Free reference from AllocPDocAccessibleParent.
  static_cast<a11y::DocAccessibleParent*>(aParent)->Release();
  return true;
}

mozilla::ipc::IPCResult BrowserParent::RecvPDocAccessibleConstructor(
    PDocAccessibleParent* aDoc, PDocAccessibleParent* aParentDoc,
    const uint64_t& aParentID,
    const MaybeDiscardedBrowsingContext& aBrowsingContext) {
#  if defined(ANDROID)
  MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
#  endif
  auto doc = static_cast<a11y::DocAccessibleParent*>(aDoc);

  // If this tab is already shutting down just mark the new actor as shutdown
  // and ignore it.  When the tab actor is destroyed it will be too.
  if (mIsDestroyed) {
    doc->MarkAsShutdown();
    return IPC_OK();
  }

  if (aParentDoc) {
    // Iframe document rendered in the same process as its embedder.
    // A document should never directly be the parent of another document.
    // There should always be an outer doc accessible child of the outer
    // document containing the child.
    MOZ_ASSERT(aParentID);
    if (!aParentID) {
      return IPC_FAIL_NO_REASON(this);
    }

    auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
    if (parentDoc->IsShutdown()) {
      // This can happen if parentDoc is an OOP iframe, but its embedder has
      // been destroyed. (DocAccessibleParent::Destroy destroys any child
      // documents.) The OOP iframe (and anything it embeds) will die soon
      // anyway, so mark this document as shutdown and ignore it.
      doc->MarkAsShutdown();
      return IPC_OK();
    }

    if (aBrowsingContext) {
      doc->SetBrowsingContext(aBrowsingContext.get_canonical());
    }

    mozilla::ipc::IPCResult added = parentDoc->AddChildDoc(doc, aParentID);
    if (!added) {
#  ifdef DEBUG
      return added;
#  else
      return IPC_OK();
#  endif
    }

#  ifdef XP_WIN
    if (a11y::nsWinUtils::IsWindowEmulationStarted()) {
      doc->SetEmulatedWindowHandle(parentDoc->GetEmulatedWindowHandle());
    }
#  endif

    return IPC_OK();
  }

  if (aBrowsingContext) {
    doc->SetBrowsingContext(aBrowsingContext.get_canonical());
  }

  if (auto* bridge = GetBrowserBridgeParent()) {
    // Iframe document rendered in a different process to its embedder.
    // In this case, we don't get aParentDoc and aParentID.
    MOZ_ASSERT(!aParentDoc && !aParentID);
    doc->SetTopLevelInContentProcess();
    a11y::ProxyCreated(doc);
    // It's possible the embedder accessible hasn't been set yet; e.g.
    // a hidden iframe. In that case, embedderDoc will be null and this will
    // be handled when the embedder is set.
    if (a11y::DocAccessibleParent* embedderDoc =
            bridge->GetEmbedderAccessibleDoc()) {
      mozilla::ipc::IPCResult added = embedderDoc->AddChildDoc(bridge);
      if (!added) {
#  ifdef DEBUG
        return added;
#  else
        return IPC_OK();
#  endif
      }
    }
    return IPC_OK();
  } else {
    // null aParentDoc means this document is at the top level in the child
    // process.  That means it makes no sense to get an id for an accessible
    // that is its parent.
    MOZ_ASSERT(!aParentID);
    if (aParentID) {
      return IPC_FAIL_NO_REASON(this);
    }

    if (auto* prevTopLevel = GetTopLevelDocAccessible()) {
      // Sometimes, we can get a new top level DocAccessibleParent before the
      // old one gets destroyed. The old one will die pretty shortly anyway,
      // so just destroy it now. If we don't do this, GetTopLevelDocAccessible()
      // might return the wrong document for a short while.
      prevTopLevel->Destroy();
    }
    doc->SetTopLevel();
    a11y::DocManager::RemoteDocAdded(doc);
#  ifdef XP_WIN
    doc->MaybeInitWindowEmulation();
#  endif
  }
  return IPC_OK();
}
#endif

already_AddRefed<PFilePickerParent> BrowserParent::AllocPFilePickerParent(
    const nsString& aTitle, const nsIFilePicker::Mode& aMode,
    const MaybeDiscarded<BrowsingContext>& aBrowsingContext) {
  RefPtr<CanonicalBrowsingContext> browsingContext =
      [&]() -> CanonicalBrowsingContext* {
    if (aBrowsingContext.IsNullOrDiscarded()) {
      return nullptr;
    }
    if (!aBrowsingContext.get_canonical()->IsOwnedByProcess(
            Manager()->ChildID())) {
      return nullptr;
    }
    return aBrowsingContext.get_canonical();
  }();
  return MakeAndAddRef<FilePickerParent>(aTitle, aMode, browsingContext);
}

already_AddRefed<PSessionStoreParent>
BrowserParent::AllocPSessionStoreParent() {
  RefPtr<BrowserSessionStore> sessionStore =
      BrowserSessionStore::GetOrCreate(mBrowsingContext->Top());
  if (!sessionStore) {
    return nullptr;
  }

  return do_AddRef(new SessionStoreParent(mBrowsingContext, sessionStore));
}

IPCResult BrowserParent::RecvNewWindowGlobal(
    ManagedEndpoint<PWindowGlobalParent>&& aEndpoint,
    const WindowGlobalInit& aInit) {
  RefPtr<CanonicalBrowsingContext> browsingContext =
      CanonicalBrowsingContext::Get(aInit.context().mBrowsingContextId);
  if (!browsingContext) {
    return IPC_FAIL(this"Cannot create for missing BrowsingContext");
  }
  if (!aInit.principal()) {
    return IPC_FAIL(this"Cannot create without valid principal");
  }

  // Ensure we never load a document with a content principal in
  // the wrong type of webIsolated process
  EnumSet<ContentParent::ValidatePrincipalOptions> validationOptions = {};
  nsCOMPtr<nsIURI> docURI = aInit.documentURI();
  if (docURI->SchemeIs("blob") || docURI->SchemeIs("chrome")) {
    // XXXckerschb TODO - Do not use SystemPrincipal for:
    // Bug 1699385: Remove allowSystem for blobs
    // Bug 1698087: chrome://devtools/content/shared/webextension-fallback.html
    // chrome reftests, e.g.
    //   * chrome://reftest/content/writing-mode/ua-style-sheet-button-1a-ref.html
    //   * chrome://reftest/content/xul-document-load/test003.xhtml
    //   * chrome://reftest/content/forms/input/text/centering-1.xhtml
    validationOptions = {ContentParent::ValidatePrincipalOptions::AllowSystem};
  }

  // Some reftests have frames inside their chrome URIs and those load
  // about:blank:
  if (xpc::IsInAutomation() && docURI->SchemeIs("about")) {
    WindowGlobalParent* wgp = browsingContext->GetParentWindowContext();
    nsAutoCString spec;
    NS_ENSURE_SUCCESS(docURI->GetSpec(spec),
                      IPC_FAIL(this"Should have spec for about: URI"));
    if (spec.Equals("about:blank") && wgp &&
        wgp->DocumentPrincipal()->IsSystemPrincipal()) {
      validationOptions = {
          ContentParent::ValidatePrincipalOptions::AllowSystem};
    }
  }

  if (!Manager()->ValidatePrincipal(aInit.principal(), validationOptions)) {
    ContentParent::LogAndAssertFailedPrincipalValidationInfo(aInit.principal(),
                                                             __func__);
  }

  // Construct our new WindowGlobalParent, bind, and initialize it.
  RefPtr<WindowGlobalParent> wgp =
      WindowGlobalParent::CreateDisconnected(aInit);
  BindPWindowGlobalEndpoint(std::move(aEndpoint), wgp);
  wgp->Init();
  return IPC_OK();
}

already_AddRefed<PVsyncParent> BrowserParent::AllocPVsyncParent() {
  return MakeAndAddRef<VsyncParent>();
}

IPCResult BrowserParent::RecvPVsyncConstructor(PVsyncParent* aActor) {
  UpdateVsyncParentVsyncDispatcher();
  return IPC_OK();
}

void BrowserParent::UpdateVsyncParentVsyncDispatcher() {
  VsyncParent* actor = static_cast<VsyncParent*>(
      LoneManagedOrNullAsserts(ManagedPVsyncParent()));
  if (!actor) {
    return;
  }

  if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
    RefPtr<VsyncDispatcher> vsyncDispatcher = widget->GetVsyncDispatcher();
    if (!vsyncDispatcher) {
      vsyncDispatcher = gfxPlatform::GetPlatform()->GetGlobalVsyncDispatcher();
    }
    actor->UpdateVsyncDispatcher(vsyncDispatcher);
  }
}

void BrowserParent::MouseEnterIntoWidget() {
  if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
    // When we mouseenter the remote target, the remote target's cursor should
    // become the current cursor.  When we mouseexit, we stop.
    mRemoteTargetSetsCursor = true;
    if (!EventStateManager::CursorSettingManagerHasLockedCursor()) {
      widget->SetCursor(mCursor);
      EventStateManager::ClearCursorSettingManager();
    }
  }

  // Mark that we have missed a mouse enter event, so that
  // the next mouse event will create a replacement mouse
  // enter event and send it to the child.
  mIsMouseEnterIntoWidgetEventSuppressed = true;
}

void BrowserParent::SendRealMouseEvent(WidgetMouseEvent& aEvent) {
  if (mIsDestroyed) {
    return;
  }

  // XXXedgar, if the synthesized mouse events could deliver to the correct
  // process directly (see
  // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably don't
  // need to check mReason then.
  if (aEvent.mReason == WidgetMouseEvent::eReal) {
    if (aEvent.mMessage == eMouseExitFromWidget) {
      // Since we are leaving this remote target, so don't need to update
      // sLastMouseRemoteTarget, and if we are sLastMouseRemoteTarget, reset it
      // to null.
      BrowserParent::UnsetLastMouseRemoteTarget(this);
    } else {
      // Last remote target should not be changed without eMouseExitFromWidget.
      MOZ_ASSERT_IF(sLastMouseRemoteTarget, sLastMouseRemoteTarget == this);
      sLastMouseRemoteTarget = this;
    }
  }

  aEvent.mRefPoint = TransformParentToChild(aEvent);

  if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
    // When we mouseenter the remote target, the remote target's cursor should
    // become the current cursor.  When we mouseexit, we stop.
    if (eMouseEnterIntoWidget == aEvent.mMessage) {
      mRemoteTargetSetsCursor = true;
      if (!EventStateManager::CursorSettingManagerHasLockedCursor()) {
        widget->SetCursor(mCursor);
        EventStateManager::ClearCursorSettingManager();
      }
    } else if (eMouseExitFromWidget == aEvent.mMessage) {
      mRemoteTargetSetsCursor = false;
    }
  }
  if (!mIsReadyToHandleInputEvents) {
    if (eMouseEnterIntoWidget == aEvent.mMessage) {
      mIsMouseEnterIntoWidgetEventSuppressed = true;
    } else if (eMouseExitFromWidget == aEvent.mMessage) {
      mIsMouseEnterIntoWidgetEventSuppressed = false;
    }
    return;
  }

  ScrollableLayerGuid guid;
  uint64_t blockId;
  ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);

  bool isInputPriorityEventEnabled = Manager()->IsInputPriorityEventEnabled();

  if (mIsMouseEnterIntoWidgetEventSuppressed) {
    // In the case that the BrowserParent suppressed the eMouseEnterWidget event
    // due to its corresponding BrowserChild wasn't ready to handle it, we have
    // to resend it when the BrowserChild is ready.
    mIsMouseEnterIntoWidgetEventSuppressed = false;
    WidgetMouseEvent localEvent(aEvent);
    localEvent.mMessage = eMouseEnterIntoWidget;
    DebugOnly<bool> ret =
        isInputPriorityEventEnabled
            ? SendRealMouseEnterExitWidgetEvent(localEvent, guid, blockId)
            : SendNormalPriorityRealMouseEnterExitWidgetEvent(localEvent, guid,
                                                              blockId);
    NS_WARNING_ASSERTION(ret, "SendRealMouseEnterExitWidgetEvent() failed");
    MOZ_ASSERT(!ret || localEvent.HasBeenPostedToRemoteProcess());
  }

  if (eMouseMove == aEvent.mMessage) {
    if (aEvent.mReason == WidgetMouseEvent::eSynthesized) {
      DebugOnly<bool> ret =
          isInputPriorityEventEnabled
              ? SendSynthMouseMoveEvent(aEvent, guid, blockId)
              : SendNormalPrioritySynthMouseMoveEvent(aEvent, guid, blockId);
      NS_WARNING_ASSERTION(ret, "SendSynthMouseMoveEvent() failed");
      MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
      return;
    }

    if (!aEvent.mFlags.mIsSynthesizedForTests) {
      DebugOnly<bool> ret =
          isInputPriorityEventEnabled
              ? SendRealMouseMoveEvent(aEvent, guid, blockId)
              : SendNormalPriorityRealMouseMoveEvent(aEvent, guid, blockId);
      NS_WARNING_ASSERTION(ret, "SendRealMouseMoveEvent() failed");
      MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
      return;
    }

    DebugOnly<bool> ret =
        isInputPriorityEventEnabled
            ? SendRealMouseMoveEventForTests(aEvent, guid, blockId)
            : SendNormalPriorityRealMouseMoveEventForTests(aEvent, guid,
                                                           blockId);
    NS_WARNING_ASSERTION(ret, "SendRealMouseMoveEventForTests() failed");
    MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
    return;
  }

  if (eMouseEnterIntoWidget == aEvent.mMessage ||
      eMouseExitFromWidget == aEvent.mMessage) {
    DebugOnly<bool> ret =
        isInputPriorityEventEnabled
            ? SendRealMouseEnterExitWidgetEvent(aEvent, guid, blockId)
            : SendNormalPriorityRealMouseEnterExitWidgetEvent(aEvent, guid,
                                                              blockId);
    NS_WARNING_ASSERTION(ret, "SendRealMouseEnterExitWidgetEvent() failed");
    MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
    return;
  }

  DebugOnly<bool> ret =
      isInputPriorityEventEnabled
          ? aEvent.mClass == ePointerEventClass
                ? SendRealPointerButtonEvent(*aEvent.AsPointerEvent(), guid,
                                             blockId)
                : SendRealMouseButtonEvent(aEvent, guid, blockId)
      : aEvent.mClass == ePointerEventClass
          ? SendNormalPriorityRealPointerButtonEvent(*aEvent.AsPointerEvent(),
                                                     guid, blockId)
          : SendNormalPriorityRealMouseButtonEvent(aEvent, guid, blockId);
  NS_WARNING_ASSERTION(ret, "SendRealMouseButtonEvent() failed");
  MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
}

LayoutDeviceToCSSScale BrowserParent::GetLayoutDeviceToCSSScale() {
  Document* doc = (mFrameElement ? mFrameElement->OwnerDoc() : nullptr);
  nsPresContext* ctx = (doc ? doc->GetPresContext() : nullptr);
  return LayoutDeviceToCSSScale(
      ctx ? (float)ctx->AppUnitsPerDevPixel() / AppUnitsPerCSSPixel() : 0.0f);
}

bool BrowserParent::QueryDropLinksForVerification() {
  // Before sending the dragEvent, we query the links being dragged and
  // store them on the parent, to make sure the child can not modify links.
  RefPtr<nsIWidget> widget = GetTopLevelWidget();
  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(widget);
  if (!dragSession) {
    NS_WARNING("No dragSession to query links for verification");
    return false;
  }

  RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
  if (!initialDataTransfer) {
    NS_WARNING("No initialDataTransfer to query links for verification");
    return false;
  }

  nsCOMPtr<nsIDroppedLinkHandler> dropHandler =
      do_GetService("@mozilla.org/content/dropped-link-handler;1");
  if (!dropHandler) {
    NS_WARNING("No dropHandler to query links for verification");
    return false;
  }

  // No more than one drop event can happen simultaneously; reset the link
  // verification array and store all links that are being dragged.
  mVerifyDropLinks.Clear();

  nsTArray<RefPtr<nsIDroppedLinkItem>> droppedLinkItems;
  dropHandler->QueryLinks(initialDataTransfer, droppedLinkItems);

  // Since the entire event is cancelled if one of the links is invalid,
  // we can store all links on the parent side without any prior
  // validation checks.
  nsresult rv = NS_OK;
  for (nsIDroppedLinkItem* item : droppedLinkItems) {
    nsString tmp;
    rv = item->GetUrl(tmp);
    if (NS_FAILED(rv)) {
      NS_WARNING("Failed to query url for verification");
      break;
    }
    mVerifyDropLinks.AppendElement(tmp);

    rv = item->GetName(tmp);
    if (NS_FAILED(rv)) {
      NS_WARNING("Failed to query name for verification");
      break;
    }
    mVerifyDropLinks.AppendElement(tmp);

    rv = item->GetType(tmp);
    if (NS_FAILED(rv)) {
      NS_WARNING("Failed to query type for verification");
      break;
    }
    mVerifyDropLinks.AppendElement(tmp);
  }
  if (NS_FAILED(rv)) {
    mVerifyDropLinks.Clear();
    return false;
  }
  return true;
}

void BrowserParent::SendRealDragEvent(WidgetDragEvent& aEvent,
                                      uint32_t aDragAction,
                                      uint32_t aDropEffect,
                                      nsIPrincipal* aPrincipal,
                                      nsIContentSecurityPolicy* aCsp) {
  if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
    return;
  }
  MOZ_ASSERT(!Manager()->IsInputPriorityEventEnabled());
  aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
  if (aEvent.mMessage == eDrop) {
    if (!QueryDropLinksForVerification()) {
      return;
    }
  }
  DebugOnly<bool> ret = PBrowserParent::SendRealDragEvent(
      aEvent, aDragAction, aDropEffect, aPrincipal, aCsp);
  NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealDragEvent() failed");
  MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
}

void BrowserParent::SendMouseWheelEvent(WidgetWheelEvent& aEvent) {
  if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
    return;
  }

  ScrollableLayerGuid guid;
  uint64_t blockId;
  ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
  aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
  DebugOnly<bool> ret =
      Manager()->IsInputPriorityEventEnabled()
          ? PBrowserParent::SendMouseWheelEvent(aEvent, guid, blockId)
          : PBrowserParent::SendNormalPriorityMouseWheelEvent(aEvent, guid,
                                                              blockId);

  NS_WARNING_ASSERTION(ret, "PBrowserParent::SendMouseWheelEvent() failed");
  MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
}

mozilla::ipc::IPCResult BrowserParent::RecvDispatchWheelEvent(
    const mozilla::WidgetWheelEvent& aEvent) {
  NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this"Unexpected event"));

  nsCOMPtr<nsIWidget> widget = GetWidget();
  if (!widget) {
    return IPC_OK();
  }

  WidgetWheelEvent localEvent(aEvent);
  localEvent.mWidget = widget;
  localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);

  widget->DispatchInputEvent(&localEvent);
  return IPC_OK();
}

mozilla::ipc::IPCResult BrowserParent::RecvDispatchMouseEvent(
    const mozilla::WidgetMouseEvent& aEvent) {
  NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this"Unexpected event"));

  nsCOMPtr<nsIWidget> widget = GetWidget();
  if (!widget) {
    return IPC_OK();
  }

  WidgetMouseEvent localEvent(aEvent);
  localEvent.mWidget = widget;
  localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);

  widget->DispatchInputEvent(&localEvent);
  return IPC_OK();
}

mozilla::ipc::IPCResult BrowserParent::RecvDispatchKeyboardEvent(
    const mozilla::WidgetKeyboardEvent& aEvent) {
  NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this"Unexpected event"));

  nsCOMPtr<nsIWidget> widget = GetWidget();
  if (!widget) {
    return IPC_OK();
  }

  WidgetKeyboardEvent localEvent(aEvent);
  localEvent.mWidget = widget;
  localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);

  widget->DispatchInputEvent(&localEvent);
  return IPC_OK();
}

mozilla::ipc::IPCResult BrowserParent::RecvDispatchTouchEvent(
    const mozilla::WidgetTouchEvent& aEvent) {
  NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this"Unexpected event"));

  nsCOMPtr<nsIWidget> widget = GetWidget();
  if (!widget) {
    return IPC_OK();
  }

  WidgetTouchEvent localEvent(aEvent);
  localEvent.mWidget = widget;

  for (uint32_t i = 0; i < localEvent.mTouches.Length(); i++) {
    localEvent.mTouches[i]->mRefPoint =
        TransformChildToParent(localEvent.mTouches[i]->mRefPoint);
  }

  widget->DispatchInputEvent(&localEvent);
  return IPC_OK();
}

mozilla::ipc::IPCResult BrowserParent::RecvRequestNativeKeyBindings(
    const uint32_t& aType, const WidgetKeyboardEvent& aEvent,
    nsTArray<CommandInt>* aCommands) {
  MOZ_ASSERT(aCommands);
  MOZ_ASSERT(aCommands->IsEmpty());

  NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this"Unexpected event"));

  NativeKeyBindingsType keyBindingsType =
      static_cast<NativeKeyBindingsType>(aType);
  switch (keyBindingsType) {
    case NativeKeyBindingsType::SingleLineEditor:
    case NativeKeyBindingsType::MultiLineEditor:
    case NativeKeyBindingsType::RichTextEditor:
      break;
    default:
      return IPC_FAIL(this"Invalid aType value");
  }

  nsCOMPtr<nsIWidget> widget = GetWidget();
  if (!widget) {
    return IPC_OK();
  }

  WidgetKeyboardEvent localEvent(aEvent);
  localEvent.mWidget = widget;

  if (NS_FAILED(widget->AttachNativeKeyEvent(localEvent))) {
    return IPC_OK();
  }

  Maybe<WritingMode> writingMode;
  if (RefPtr<widget::TextEventDispatcher> dispatcher =
          widget->GetTextEventDispatcher()) {
    writingMode = dispatcher->MaybeQueryWritingModeAtSelection();
  }
  if (localEvent.InitEditCommandsFor(keyBindingsType, writingMode)) {
    *aCommands = localEvent.EditCommandsConstRef(keyBindingsType).Clone();
  }

  return IPC_OK();
}

class SynthesizedEventObserver : public nsIObserver {
  NS_DECL_ISUPPORTS

 public:
  SynthesizedEventObserver(BrowserParent* aBrowserParent,
                           const uint64_t& aObserverId)
      : mBrowserParent(aBrowserParent), mObserverId(aObserverId) {
    MOZ_ASSERT(mBrowserParent);
  }

  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
                     const char16_t* aData) override {
    if (!mBrowserParent || !mObserverId) {
      // We already sent the notification, or we don't actually need to
      // send any notification at all.
      return NS_OK;
    }

    if (mBrowserParent->IsDestroyed()) {
      // If this happens it's probably a bug in the test that's triggering this.
      NS_WARNING(
          "BrowserParent was unexpectedly destroyed during event "
          "synthesization!");
    } else if (!mBrowserParent->SendNativeSynthesisResponse(
                   mObserverId, nsCString(aTopic))) {
      NS_WARNING("Unable to send native event synthesization response!");
    }
    // Null out browserParent to indicate we already sent the response
    mBrowserParent = nullptr;
    return NS_OK;
  }

 private:
  virtual ~SynthesizedEventObserver() = default;

  RefPtr<BrowserParent> mBrowserParent;
  uint64_t mObserverId;
};

NS_IMPL_ISUPPORTS(SynthesizedEventObserver, nsIObserver)

class MOZ_STACK_CLASS AutoSynthesizedEventResponder {
 public:
  AutoSynthesizedEventResponder(BrowserParent* aBrowserParent,
                                const uint64_t& aObserverId, const char* aTopic)
      : mObserver(new SynthesizedEventObserver(aBrowserParent, aObserverId)),
        mTopic(aTopic) {}

  ~AutoSynthesizedEventResponder() {
    // This may be a no-op if the observer already sent a response.
    mObserver->Observe(nullptr, mTopic, nullptr);
  }

  nsIObserver* GetObserver() { return mObserver; }

 private:
  nsCOMPtr<nsIObserver> mObserver;
  const char* mTopic;
};

mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeKeyEvent(
    const int32_t& aNativeKeyboardLayout, const int32_t& aNativeKeyCode,
    const uint32_t& aModifierFlags, const nsString& aCharacters,
    const nsString& aUnmodifiedCharacters, const uint64_t& aObserverId) {
  NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this"Unexpected event"));

  AutoSynthesizedEventResponder responder(this, aObserverId, "keyevent");
  nsCOMPtr<nsIWidget> widget = GetWidget();
  if (widget) {
    widget->SynthesizeNativeKeyEvent(
        aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags, aCharacters,
        aUnmodifiedCharacters, responder.GetObserver());
  }
  return IPC_OK();
}

mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseEvent(
    const LayoutDeviceIntPoint& aPoint, const uint32_t& aNativeMessage,
    const int16_t& aButton, const uint32_t& aModifierFlags,
    const uint64_t& aObserverId) {
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=91 G=91

¤ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.