tor-browser

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

nsDOMWindowUtils.cpp (155671B)


      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 "nsDOMWindowUtils.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "CubebDeviceEnumerator.h"
     12 #include "LayoutConstants.h"
     13 #include "MobileViewportManager.h"
     14 #include "js/Object.h"                         // JS::GetClass
     15 #include "js/experimental/PCCountProfiling.h"  // JS::{Start,Stop}PCCountProfiling, JS::PurgePCCounts, JS::GetPCCountScript{Count,Summary,Contents}
     16 #include "mozilla/Base64.h"
     17 #include "mozilla/ChaosMode.h"
     18 #include "mozilla/EventStateManager.h"
     19 #include "mozilla/InputTaskManager.h"
     20 #include "mozilla/Logging.h"
     21 #include "mozilla/MiscEvents.h"
     22 #include "mozilla/MouseEvents.h"
     23 #include "mozilla/PresShell.h"
     24 #include "mozilla/PresShellInlines.h"
     25 #include "mozilla/ScrollContainerFrame.h"
     26 #include "mozilla/ServoStyleSet.h"
     27 #include "mozilla/StaticPrefs_layout.h"
     28 #include "mozilla/StaticPrefs_test.h"
     29 #include "mozilla/StyleAnimationValue.h"
     30 #include "mozilla/TextEventDispatcher.h"
     31 #include "mozilla/TextEvents.h"
     32 #include "mozilla/TouchEvents.h"
     33 #include "mozilla/css/Loader.h"
     34 #include "mozilla/dom/Animation.h"
     35 #include "mozilla/dom/BindingDeclarations.h"
     36 #include "mozilla/dom/BlobBinding.h"
     37 #include "mozilla/dom/DOMCollectedFramesBinding.h"
     38 #include "mozilla/dom/DOMRect.h"
     39 #include "mozilla/dom/DocumentInlines.h"
     40 #include "mozilla/dom/DocumentTimeline.h"
     41 #include "mozilla/dom/Event.h"
     42 #include "mozilla/dom/File.h"
     43 #include "mozilla/dom/FileBinding.h"
     44 #include "mozilla/dom/FunctionBinding.h"
     45 #include "mozilla/dom/MouseEventBinding.h"
     46 #include "mozilla/dom/Touch.h"
     47 #include "mozilla/dom/UserActivation.h"
     48 #include "mozilla/layers/APZCCallbackHelper.h"
     49 #include "mozilla/layers/CompositorBridgeChild.h"
     50 #include "mozilla/layers/PCompositorBridgeTypes.h"
     51 #include "mozilla/layers/TouchActionHelper.h"
     52 #include "mozilla/media/MediaUtils.h"
     53 #include "nsCSSProps.h"
     54 #include "nsCaret.h"
     55 #include "nsCharsetSource.h"
     56 #include "nsComputedDOMStyle.h"
     57 #include "nsContentList.h"
     58 #include "nsContentUtils.h"
     59 #include "nsDeviceContext.h"
     60 #include "nsError.h"
     61 #include "nsFocusManager.h"
     62 #include "nsFrameManager.h"
     63 #include "nsGlobalWindowOuter.h"
     64 #include "nsIDocShell.h"
     65 #include "nsIFrame.h"
     66 #include "nsIObjectLoadingContent.h"
     67 #include "nsIWidget.h"
     68 #include "nsJSEnvironment.h"
     69 #include "nsJSUtils.h"
     70 #include "nsLayoutUtils.h"
     71 #include "nsMenuPopupFrame.h"
     72 #include "nsPresContext.h"
     73 #include "nsQueryContentEventResult.h"
     74 #include "nsQueryObject.h"
     75 #include "nsRefreshDriver.h"
     76 #include "nsStyleUtil.h"
     77 
     78 #if defined(MOZ_WIDGET_GTK)
     79 #  include <gdk/gdk.h>
     80 #  if defined(MOZ_X11)
     81 #    include <gdk/gdkx.h>
     82 
     83 #    include "X11UndefineNone.h"
     84 #  endif
     85 #endif
     86 
     87 #include "mozilla/dom/AudioDeviceInfo.h"
     88 #include "mozilla/dom/BrowserChild.h"
     89 #include "mozilla/dom/ContentChild.h"
     90 #include "mozilla/dom/Element.h"
     91 #include "mozilla/dom/IDBFactoryBinding.h"
     92 #include "mozilla/dom/IndexedDatabaseManager.h"
     93 #include "mozilla/dom/PermissionMessageUtils.h"
     94 #include "mozilla/dom/Text.h"
     95 #include "mozilla/dom/quota/PersistenceType.h"
     96 #include "mozilla/dom/quota/PrincipalUtils.h"
     97 #include "mozilla/layers/FrameUniformityData.h"
     98 #include "nsIFormControl.h"
     99 #include "nsPrintfCString.h"
    100 #include "nsViewportInfo.h"
    101 // #include "nsWidgetsCID.h"
    102 #include "HTMLCanvasElement.h"
    103 #include "HTMLImageElement.h"
    104 #include "mozilla/CSSPropertyId.h"
    105 #include "mozilla/CycleCollectedJSContext.h"
    106 #include "mozilla/DisplayPortUtils.h"
    107 #include "mozilla/IMEContentObserver.h"
    108 #include "mozilla/IMEStateManager.h"
    109 #include "mozilla/Preferences.h"
    110 #include "mozilla/PreloadedStyleSheet.h"
    111 #include "mozilla/ProfilerLabels.h"
    112 #include "mozilla/ProfilerMarkers.h"
    113 #include "mozilla/RDDProcessManager.h"
    114 #include "mozilla/ServoBindings.h"
    115 #include "mozilla/StyleSheetInlines.h"
    116 #include "mozilla/ViewportUtils.h"
    117 #include "mozilla/WheelHandlingHelper.h"
    118 #include "mozilla/css/ImageLoader.h"
    119 #include "mozilla/dom/BrowsingContextGroup.h"
    120 #include "mozilla/dom/Document.h"
    121 #include "mozilla/dom/Promise.h"
    122 #include "mozilla/dom/TimeoutManager.h"
    123 #include "mozilla/gfx/GPUProcessManager.h"
    124 #include "mozilla/gfx/gfxVars.h"
    125 #include "mozilla/layers/IAPZCTreeManager.h"  // for layers::ZoomToRectBehavior
    126 #include "mozilla/layers/WebRenderBridgeChild.h"
    127 #include "mozilla/layers/WebRenderLayerManager.h"
    128 #include "nsCSSPseudoElements.h"  // for PseudoStyleType
    129 #include "nsContentPermissionHelper.h"
    130 #include "nsDisplayList.h"
    131 #include "nsIBaseWindow.h"
    132 #include "nsIDocShellTreeOwner.h"
    133 #include "nsIInterfaceRequestorUtils.h"
    134 #include "nsNetUtil.h"
    135 #include "nsROCSSPrimitiveValue.h"
    136 
    137 #ifdef XP_WIN
    138 #  include <direct.h>
    139 #else
    140 #  include <sys/stat.h>
    141 #endif
    142 
    143 #ifdef XP_WIN
    144 #  undef GetClassName
    145 #endif
    146 
    147 using namespace mozilla;
    148 using namespace mozilla::dom;
    149 using namespace mozilla::ipc;
    150 using namespace mozilla::layers;
    151 using namespace mozilla::widget;
    152 using namespace mozilla::gfx;
    153 
    154 static LazyLogModule sApzZoomToFocusedInputLog("apz.zoomtofocusedinput");
    155 #define APZZTFI_LOG(...) \
    156  MOZ_LOG(sApzZoomToFocusedInputLog, LogLevel::Debug, (__VA_ARGS__))
    157 
    158 class gfxContext;
    159 
    160 class OldWindowSize : public LinkedListElement<OldWindowSize> {
    161 public:
    162  static void Set(nsIWeakReference* aWindowRef, const nsSize& aSize) {
    163    OldWindowSize* item = GetItem(aWindowRef);
    164    if (item) {
    165      item->mSize = aSize;
    166    } else {
    167      item = new OldWindowSize(aWindowRef, aSize);
    168      sList.insertBack(item);
    169    }
    170  }
    171 
    172  static nsSize GetAndRemove(nsIWeakReference* aWindowRef) {
    173    nsSize result;
    174    if (OldWindowSize* item = GetItem(aWindowRef)) {
    175      result = item->mSize;
    176      delete item;
    177    }
    178    return result;
    179  }
    180 
    181 private:
    182  explicit OldWindowSize(nsIWeakReference* aWindowRef, const nsSize& aSize)
    183      : mWindowRef(aWindowRef), mSize(aSize) {}
    184  ~OldWindowSize() = default;
    185  ;
    186 
    187  static OldWindowSize* GetItem(nsIWeakReference* aWindowRef) {
    188    OldWindowSize* item = sList.getFirst();
    189    while (item && item->mWindowRef != aWindowRef) {
    190      item = item->getNext();
    191    }
    192    return item;
    193  }
    194 
    195  static LinkedList<OldWindowSize> sList;
    196  nsWeakPtr mWindowRef;
    197  nsSize mSize;
    198 };
    199 
    200 namespace {
    201 
    202 class NativeInputRunnable final : public PrioritizableRunnable {
    203  explicit NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent);
    204  ~NativeInputRunnable() = default;
    205 
    206 public:
    207  static already_AddRefed<nsIRunnable> Create(
    208      already_AddRefed<nsIRunnable>&& aEvent);
    209 };
    210 
    211 NativeInputRunnable::NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent)
    212    : PrioritizableRunnable(std::move(aEvent),
    213                            nsIRunnablePriority::PRIORITY_INPUT_HIGH) {}
    214 
    215 /* static */
    216 already_AddRefed<nsIRunnable> NativeInputRunnable::Create(
    217    already_AddRefed<nsIRunnable>&& aEvent) {
    218  MOZ_ASSERT(NS_IsMainThread());
    219  nsCOMPtr<nsIRunnable> event(new NativeInputRunnable(std::move(aEvent)));
    220  return event.forget();
    221 }
    222 
    223 }  // unnamed namespace
    224 
    225 MOZ_RUNINIT LinkedList<OldWindowSize> OldWindowSize::sList;
    226 
    227 NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
    228  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWindowUtils)
    229  NS_INTERFACE_MAP_ENTRY(nsIDOMWindowUtils)
    230  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
    231 NS_INTERFACE_MAP_END
    232 
    233 NS_IMPL_ADDREF(nsDOMWindowUtils)
    234 NS_IMPL_RELEASE(nsDOMWindowUtils)
    235 
    236 nsDOMWindowUtils::nsDOMWindowUtils(nsGlobalWindowOuter* aWindow) {
    237  nsCOMPtr<nsISupports> supports = do_QueryObject(aWindow);
    238  mWindow = do_GetWeakReference(supports);
    239 }
    240 
    241 nsDOMWindowUtils::~nsDOMWindowUtils() { OldWindowSize::GetAndRemove(mWindow); }
    242 
    243 nsIDocShell* nsDOMWindowUtils::GetDocShell() {
    244  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
    245  if (!window) {
    246    return nullptr;
    247  }
    248  return window->GetDocShell();
    249 }
    250 
    251 PresShell* nsDOMWindowUtils::GetPresShell() {
    252  nsIDocShell* docShell = GetDocShell();
    253  if (!docShell) {
    254    return nullptr;
    255  }
    256  return docShell->GetPresShell();
    257 }
    258 
    259 nsPresContext* nsDOMWindowUtils::GetPresContext() {
    260  nsIDocShell* docShell = GetDocShell();
    261  if (!docShell) {
    262    return nullptr;
    263  }
    264  return docShell->GetPresContext();
    265 }
    266 
    267 Document* nsDOMWindowUtils::GetDocument() {
    268  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
    269  if (!window) {
    270    return nullptr;
    271  }
    272  return window->GetExtantDoc();
    273 }
    274 
    275 WebRenderBridgeChild* nsDOMWindowUtils::GetWebRenderBridge() {
    276  if (nsIWidget* widget = GetWidget()) {
    277    if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
    278      if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
    279        return wr->WrBridge();
    280      }
    281    }
    282  }
    283  return nullptr;
    284 }
    285 
    286 CompositorBridgeChild* nsDOMWindowUtils::GetCompositorBridge() {
    287  if (nsIWidget* widget = GetWidget()) {
    288    if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
    289      if (CompositorBridgeChild* cbc = renderer->GetCompositorBridgeChild()) {
    290        return cbc;
    291      }
    292    }
    293  }
    294  return nullptr;
    295 }
    296 
    297 nsresult nsDOMWindowUtils::GetWidgetOpaqueRegion(
    298    nsTArray<RefPtr<DOMRect>>& aRects) {
    299  const nsPresContext* pc = GetPresContext();
    300  nsIWidget* widget = GetWidget();
    301  if (!widget || !pc) {
    302    return NS_ERROR_FAILURE;
    303  }
    304  auto AddRect = [&](const LayoutDeviceIntRect& aRect) {
    305    RefPtr rect = new DOMRect(mWindow);
    306    CSSRect cssRect = aRect / pc->CSSToDevPixelScale();
    307    rect->SetRect(cssRect.x, cssRect.y, cssRect.width, cssRect.height);
    308    aRects.AppendElement(std::move(rect));
    309  };
    310  if (widget->GetTransparencyMode() == TransparencyMode::Opaque) {
    311    AddRect(
    312        LayoutDeviceIntRect(LayoutDeviceIntPoint(), widget->GetClientSize()));
    313    return NS_OK;
    314  }
    315  auto region = widget->GetOpaqueRegionForTesting();
    316  for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
    317    AddRect(iter.Get());
    318  }
    319  return NS_OK;
    320 }
    321 
    322 NS_IMETHODIMP
    323 nsDOMWindowUtils::GetLastOverWindowPointerLocationInCSSPixels(float* aX,
    324                                                              float* aY) {
    325  const PresShell* presShell = GetPresShell();
    326  const nsPresContext* presContext = GetPresContext();
    327 
    328  if (!presShell || !presContext) {
    329    return NS_ERROR_FAILURE;
    330  }
    331 
    332  const nsPoint& lastOverWindowPointerLocation =
    333      presShell->GetLastOverWindowPointerLocation();
    334 
    335  if (lastOverWindowPointerLocation.X() == NS_UNCONSTRAINEDSIZE &&
    336      lastOverWindowPointerLocation.Y() == NS_UNCONSTRAINEDSIZE) {
    337    *aX = 0;
    338    *aY = 0;
    339  } else {
    340    const CSSPoint lastOverWindowPointerLocationInCSSPixels =
    341        CSSPoint::FromAppUnits(lastOverWindowPointerLocation);
    342    *aX = lastOverWindowPointerLocationInCSSPixels.X();
    343    *aY = lastOverWindowPointerLocationInCSSPixels.Y();
    344  }
    345 
    346  return NS_OK;
    347 }
    348 
    349 NS_IMETHODIMP
    350 nsDOMWindowUtils::SyncFlushCompositor() {
    351  if (nsIWidget* widget = GetWidget()) {
    352    if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
    353      if (KnowsCompositor* kc = renderer->AsKnowsCompositor()) {
    354        kc->SyncWithCompositor();
    355      }
    356    }
    357  }
    358  return NS_OK;
    359 }
    360 
    361 NS_IMETHODIMP
    362 nsDOMWindowUtils::GetImageAnimationMode(uint16_t* aMode) {
    363  NS_ENSURE_ARG_POINTER(aMode);
    364  *aMode = 0;
    365  nsPresContext* presContext = GetPresContext();
    366  if (presContext) {
    367    *aMode = presContext->ImageAnimationMode();
    368    return NS_OK;
    369  }
    370  return NS_ERROR_NOT_AVAILABLE;
    371 }
    372 
    373 NS_IMETHODIMP
    374 nsDOMWindowUtils::SetImageAnimationMode(uint16_t aMode) {
    375  nsPresContext* presContext = GetPresContext();
    376  if (presContext) {
    377    presContext->SetImageAnimationMode(aMode);
    378    return NS_OK;
    379  }
    380  return NS_ERROR_NOT_AVAILABLE;
    381 }
    382 
    383 NS_IMETHODIMP
    384 nsDOMWindowUtils::GetDocCharsetIsForced(bool* aIsForced) {
    385  *aIsForced = false;
    386 
    387  Document* doc = GetDocument();
    388  if (doc) {
    389    auto source = doc->GetDocumentCharacterSetSource();
    390    *aIsForced = source == kCharsetFromInitialUserForcedAutoDetection ||
    391                 source == kCharsetFromFinalUserForcedAutoDetection;
    392  }
    393  return NS_OK;
    394 }
    395 
    396 NS_IMETHODIMP
    397 nsDOMWindowUtils::GetPhysicalMillimeterInCSSPixels(float* aPhysicalMillimeter) {
    398  nsPresContext* presContext = GetPresContext();
    399  if (!presContext) {
    400    return NS_ERROR_NOT_AVAILABLE;
    401  }
    402 
    403  *aPhysicalMillimeter = nsPresContext::AppUnitsToFloatCSSPixels(
    404      presContext->PhysicalMillimetersToAppUnits(1));
    405  return NS_OK;
    406 }
    407 
    408 NS_IMETHODIMP
    409 nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName,
    410                                      nsAString& aValue) {
    411  Document* doc = GetDocument();
    412  if (doc) {
    413    RefPtr<nsAtom> name = NS_Atomize(aName);
    414    doc->GetHeaderData(name, aValue);
    415    return NS_OK;
    416  }
    417 
    418  aValue.Truncate();
    419  return NS_OK;
    420 }
    421 
    422 NS_IMETHODIMP
    423 nsDOMWindowUtils::UpdateLayerTree() {
    424  FlushLayoutWithoutThrottledAnimations();
    425  if (RefPtr<PresShell> ps = GetPresShell()) {
    426    nsAutoScriptBlocker scriptBlocker;
    427    RefPtr renderer = ps->GetWindowRenderer();
    428    ps->PaintAndRequestComposite(ps->GetRootFrame(), renderer,
    429                                 PaintFlags::PaintSyncDecodeImages);
    430    renderer->WaitOnTransactionProcessed();
    431  }
    432  return NS_OK;
    433 }
    434 
    435 NS_IMETHODIMP
    436 nsDOMWindowUtils::GetDocumentViewerSize(uint32_t* aDisplayWidth,
    437                                        uint32_t* aDisplayHeight) {
    438  PresShell* presShell = GetPresShell();
    439  LayoutDeviceIntSize displaySize;
    440 
    441  if (!presShell || !nsLayoutUtils::GetDocumentViewerSize(
    442                        presShell->GetPresContext(), displaySize)) {
    443    return NS_ERROR_FAILURE;
    444  }
    445 
    446  *aDisplayWidth = displaySize.width;
    447  *aDisplayHeight = displaySize.height;
    448 
    449  return NS_OK;
    450 }
    451 
    452 NS_IMETHODIMP
    453 nsDOMWindowUtils::GetViewportInfo(uint32_t aDisplayWidth,
    454                                  uint32_t aDisplayHeight, double* aDefaultZoom,
    455                                  bool* aAllowZoom, double* aMinZoom,
    456                                  double* aMaxZoom, uint32_t* aWidth,
    457                                  uint32_t* aHeight, bool* aAutoSize) {
    458  Document* doc = GetDocument();
    459  NS_ENSURE_STATE(doc);
    460 
    461  nsViewportInfo info =
    462      doc->GetViewportInfo(ScreenIntSize(aDisplayWidth, aDisplayHeight));
    463  *aDefaultZoom = info.GetDefaultZoom().scale;
    464  *aAllowZoom = info.IsZoomAllowed();
    465  *aMinZoom = info.GetMinZoom().scale;
    466  *aMaxZoom = info.GetMaxZoom().scale;
    467  CSSIntSize size = gfx::RoundedToInt(info.GetSize());
    468  *aWidth = size.width;
    469  *aHeight = size.height;
    470  *aAutoSize = info.IsAutoSizeEnabled();
    471  return NS_OK;
    472 }
    473 
    474 NS_IMETHODIMP
    475 nsDOMWindowUtils::GetViewportFitInfo(nsAString& aViewportFit) {
    476  Document* doc = GetDocument();
    477  NS_ENSURE_STATE(doc);
    478 
    479  ViewportMetaData metaData = doc->GetViewportMetaData();
    480  if (metaData.mViewportFit.EqualsLiteral("contain")) {
    481    aViewportFit.AssignLiteral("contain");
    482  } else if (metaData.mViewportFit.EqualsLiteral("cover")) {
    483    aViewportFit.AssignLiteral("cover");
    484  } else {
    485    aViewportFit.AssignLiteral("auto");
    486  }
    487  return NS_OK;
    488 }
    489 
    490 NS_IMETHODIMP
    491 nsDOMWindowUtils::SetMousewheelAutodir(Element* aElement, bool aEnabled,
    492                                       bool aHonourRoot) {
    493  aElement->SetProperty(nsGkAtoms::forceMousewheelAutodir,
    494                        reinterpret_cast<void*>(aEnabled));
    495  aElement->SetProperty(nsGkAtoms::forceMousewheelAutodirHonourRoot,
    496                        reinterpret_cast<void*>(aHonourRoot));
    497  return NS_OK;
    498 }
    499 
    500 NS_IMETHODIMP
    501 nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
    502                                           float aWidthPx, float aHeightPx,
    503                                           Element* aElement,
    504                                           uint32_t aPriority) {
    505  PresShell* presShell = GetPresShell();
    506  if (!presShell) {
    507    return NS_ERROR_FAILURE;
    508  }
    509 
    510  if (!aElement) {
    511    return NS_ERROR_INVALID_ARG;
    512  }
    513 
    514  if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
    515    return NS_ERROR_INVALID_ARG;
    516  }
    517 
    518  bool hadDisplayPort = false;
    519  bool wasPainted = false;
    520  nsRect oldDisplayPort;
    521  {
    522    DisplayPortPropertyData* currentData =
    523        static_cast<DisplayPortPropertyData*>(
    524            aElement->GetProperty(nsGkAtoms::DisplayPort));
    525    if (currentData) {
    526      if (currentData->mPriority > aPriority) {
    527        return NS_OK;
    528      }
    529      hadDisplayPort = true;
    530      oldDisplayPort = currentData->mRect;
    531      wasPainted = currentData->mPainted;
    532    }
    533  }
    534 
    535  nsRect displayport(nsPresContext::CSSPixelsToAppUnits(aXPx),
    536                     nsPresContext::CSSPixelsToAppUnits(aYPx),
    537                     nsPresContext::CSSPixelsToAppUnits(aWidthPx),
    538                     nsPresContext::CSSPixelsToAppUnits(aHeightPx));
    539 
    540  aElement->RemoveProperty(nsGkAtoms::MinimalDisplayPort);
    541  aElement->SetProperty(
    542      nsGkAtoms::DisplayPort,
    543      new DisplayPortPropertyData(displayport, aPriority, wasPainted),
    544      nsINode::DeleteProperty<DisplayPortPropertyData>);
    545 
    546  DisplayPortUtils::InvalidateForDisplayPortChange(aElement, hadDisplayPort,
    547                                                   oldDisplayPort, displayport);
    548 
    549  nsIFrame* rootFrame = presShell->GetRootFrame();
    550  if (rootFrame) {
    551    rootFrame->SchedulePaint();
    552 
    553    // If we are hiding something that is a display root then send empty paint
    554    // transaction in order to release retained layers because it won't get
    555    // any more paint requests when it is hidden.
    556    if (displayport.IsEmpty() &&
    557        rootFrame == nsLayoutUtils::GetDisplayRootFrame(rootFrame)) {
    558      nsCOMPtr<nsIWidget> widget = GetWidget();
    559      if (widget) {
    560        using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
    561        nsLayoutUtils::PaintFrame(
    562            nullptr, rootFrame, nsRegion(), NS_RGB(255, 255, 255),
    563            nsDisplayListBuilderMode::Painting, PaintFrameFlags::WidgetLayers);
    564      }
    565    }
    566  }
    567 
    568  return NS_OK;
    569 }
    570 
    571 NS_IMETHODIMP
    572 nsDOMWindowUtils::SetDisplayPortMarginsForElement(
    573    float aLeftMargin, float aTopMargin, float aRightMargin,
    574    float aBottomMargin, Element* aElement, uint32_t aPriority) {
    575  PresShell* presShell = GetPresShell();
    576  if (!presShell) {
    577    return NS_ERROR_FAILURE;
    578  }
    579 
    580  if (!aElement) {
    581    return NS_ERROR_INVALID_ARG;
    582  }
    583 
    584  if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
    585    return NS_ERROR_INVALID_ARG;
    586  }
    587 
    588  // Note order change of arguments between our function signature and
    589  // ScreenMargin constructor.
    590  ScreenMargin displayportMargins(aTopMargin, aRightMargin, aBottomMargin,
    591                                  aLeftMargin);
    592 
    593  DisplayPortUtils::SetDisplayPortMargins(
    594      aElement, presShell,
    595      DisplayPortMargins::ForContent(aElement, displayportMargins),
    596      DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes, aPriority);
    597 
    598  return NS_OK;
    599 }
    600 
    601 NS_IMETHODIMP
    602 nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX, int32_t aY,
    603                                               int32_t aWidth, int32_t aHeight,
    604                                               Element* aElement) {
    605  PresShell* presShell = GetPresShell();
    606  if (!presShell) {
    607    return NS_ERROR_FAILURE;
    608  }
    609 
    610  if (!aElement) {
    611    return NS_ERROR_INVALID_ARG;
    612  }
    613 
    614  if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
    615    return NS_ERROR_INVALID_ARG;
    616  }
    617 
    618  DisplayPortUtils::SetDisplayPortBase(aElement,
    619                                       nsRect(aX, aY, aWidth, aHeight));
    620 
    621  return NS_OK;
    622 }
    623 
    624 NS_IMETHODIMP
    625 nsDOMWindowUtils::GetScrollbarSizes(Element* aElement,
    626                                    uint32_t* aOutVerticalScrollbarWidth,
    627                                    uint32_t* aOutHorizontalScrollbarHeight) {
    628  ScrollContainerFrame* scrollContainerFrame =
    629      nsLayoutUtils::FindScrollContainerFrameFor(aElement);
    630  if (!scrollContainerFrame) {
    631    return NS_ERROR_INVALID_ARG;
    632  }
    633 
    634  CSSIntMargin scrollbarSizes = RoundedToInt(
    635      CSSMargin::FromAppUnits(scrollContainerFrame->GetActualScrollbarSizes(
    636          ScrollContainerFrame::ScrollbarSizesOptions::
    637              INCLUDE_VISUAL_VIEWPORT_SCROLLBARS)));
    638  *aOutVerticalScrollbarWidth = scrollbarSizes.LeftRight();
    639  *aOutHorizontalScrollbarHeight = scrollbarSizes.TopBottom();
    640 
    641  return NS_OK;
    642 }
    643 
    644 NS_IMETHODIMP
    645 nsDOMWindowUtils::SetResolutionAndScaleTo(float aResolution) {
    646  PresShell* presShell = GetPresShell();
    647  if (!presShell) {
    648    return NS_ERROR_FAILURE;
    649  }
    650 
    651  presShell->SetResolutionAndScaleTo(aResolution, ResolutionChangeOrigin::Test);
    652 
    653  return NS_OK;
    654 }
    655 
    656 NS_IMETHODIMP
    657 nsDOMWindowUtils::SetRestoreResolution(float aResolution,
    658                                       uint32_t aDisplayWidth,
    659                                       uint32_t aDisplayHeight) {
    660  PresShell* presShell = GetPresShell();
    661  if (!presShell) {
    662    return NS_ERROR_FAILURE;
    663  }
    664 
    665  presShell->SetRestoreResolution(
    666      aResolution, LayoutDeviceIntSize(aDisplayWidth, aDisplayHeight));
    667 
    668  return NS_OK;
    669 }
    670 
    671 NS_IMETHODIMP
    672 nsDOMWindowUtils::GetResolution(float* aResolution) {
    673  PresShell* presShell = GetPresShell();
    674  if (!presShell) {
    675    return NS_ERROR_FAILURE;
    676  }
    677 
    678  *aResolution = presShell->GetResolution();
    679 
    680  return NS_OK;
    681 }
    682 
    683 NS_IMETHODIMP
    684 nsDOMWindowUtils::SetIsFirstPaint(bool aIsFirstPaint) {
    685  if (PresShell* presShell = GetPresShell()) {
    686    presShell->SetIsFirstPaint(aIsFirstPaint);
    687    return NS_OK;
    688  }
    689  return NS_ERROR_FAILURE;
    690 }
    691 
    692 NS_IMETHODIMP
    693 nsDOMWindowUtils::GetIsFirstPaint(bool* aIsFirstPaint) {
    694  if (PresShell* presShell = GetPresShell()) {
    695    *aIsFirstPaint = presShell->GetIsFirstPaint();
    696    return NS_OK;
    697  }
    698  return NS_ERROR_FAILURE;
    699 }
    700 
    701 NS_IMETHODIMP
    702 nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) {
    703  if (PresShell* presShell = GetPresShell()) {
    704    *aPresShellId = presShell->GetPresShellId();
    705    return NS_OK;
    706  }
    707  return NS_ERROR_FAILURE;
    708 }
    709 
    710 NS_IMETHODIMP
    711 nsDOMWindowUtils::IsCORSSafelistedRequestHeader(const nsACString& aName,
    712                                                const nsACString& aValue,
    713                                                bool* aRetVal) {
    714  NS_ENSURE_ARG_POINTER(aRetVal);
    715  *aRetVal = nsContentUtils::IsCORSSafelistedRequestHeader(aName, aValue);
    716  return NS_OK;
    717 }
    718 
    719 NS_IMETHODIMP
    720 nsDOMWindowUtils::SendWheelEvent(float aX, float aY, double aDeltaX,
    721                                 double aDeltaY, double aDeltaZ,
    722                                 uint32_t aDeltaMode, int32_t aModifiers,
    723                                 int32_t aLineOrPageDeltaX,
    724                                 int32_t aLineOrPageDeltaY, uint32_t aOptions,
    725                                 nsISynthesizedEventCallback* aCallback) {
    726  if (XRE_IsContentProcess() && aCallback &&
    727      ((aOptions & WHEEL_EVENT_ASYNC_ENABLED) ||
    728       StaticPrefs::test_events_async_enabled())) {
    729    NS_WARNING(
    730        "nsDOMWindowUtils::SendWheelEvent() does not support being called in "
    731        "the content process with both a callback and async enabled");
    732    return NS_ERROR_FAILURE;
    733  }
    734 
    735  // get the widget to send the event to
    736  nsPoint offset;
    737  nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
    738  if (!widget) {
    739    return NS_ERROR_NULL_POINTER;
    740  }
    741 
    742  mozilla::widget::AutoSynthesizedEventCallbackNotifier notifier(aCallback);
    743 
    744  WidgetWheelEvent wheelEvent(true, eWheel, widget);
    745  wheelEvent.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
    746  wheelEvent.mDeltaX = aDeltaX;
    747  wheelEvent.mDeltaY = aDeltaY;
    748  wheelEvent.mDeltaZ = aDeltaZ;
    749  wheelEvent.mDeltaMode = aDeltaMode;
    750  wheelEvent.mIsMomentum = (aOptions & WHEEL_EVENT_CAUSED_BY_MOMENTUM) != 0;
    751  wheelEvent.mIsNoLineOrPageDelta =
    752      (aOptions & WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE) != 0;
    753  wheelEvent.mCustomizedByUserPrefs =
    754      (aOptions & WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS) != 0;
    755  wheelEvent.mLineOrPageDeltaX = aLineOrPageDeltaX;
    756  wheelEvent.mLineOrPageDeltaY = aLineOrPageDeltaY;
    757  wheelEvent.mCallbackId = notifier.SaveCallback();
    758 
    759  nsPresContext* presContext = GetPresContext();
    760  NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
    761 
    762  wheelEvent.mRefPoint =
    763      nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
    764 
    765  if ((aOptions & WHEEL_EVENT_ASYNC_ENABLED) ||
    766      StaticPrefs::test_events_async_enabled()) {
    767    widget->DispatchInputEvent(&wheelEvent);
    768  } else {
    769    widget->DispatchEvent(&wheelEvent);
    770  }
    771 
    772  // The callback ID may be cleared when the event also needs to be dispatched
    773  // to a content process. In such cases, the callback will be notified after
    774  // the event has been dispatched in the target content process.
    775  if (wheelEvent.mCallbackId.isSome()) {
    776    mozilla::widget::AutoSynthesizedEventCallbackNotifier::NotifySavedCallback(
    777        wheelEvent.mCallbackId.ref());
    778  }
    779 
    780  if (widget->AsyncPanZoomEnabled()) {
    781    // Computing overflow deltas is not compatible with APZ, so if APZ is
    782    // enabled, we skip testing it.
    783    return NS_OK;
    784  }
    785 
    786  bool failedX = false;
    787  if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_ZERO) &&
    788      wheelEvent.mOverflowDeltaX != 0) {
    789    failedX = true;
    790  }
    791  if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_POSITIVE) &&
    792      wheelEvent.mOverflowDeltaX <= 0) {
    793    failedX = true;
    794  }
    795  if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_NEGATIVE) &&
    796      wheelEvent.mOverflowDeltaX >= 0) {
    797    failedX = true;
    798  }
    799  bool failedY = false;
    800  if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_ZERO) &&
    801      wheelEvent.mOverflowDeltaY != 0) {
    802    failedY = true;
    803  }
    804  if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_POSITIVE) &&
    805      wheelEvent.mOverflowDeltaY <= 0) {
    806    failedY = true;
    807  }
    808  if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_NEGATIVE) &&
    809      wheelEvent.mOverflowDeltaY >= 0) {
    810    failedY = true;
    811  }
    812 
    813 #ifdef DEBUG
    814  if (failedX) {
    815    nsPrintfCString debugMsg("SendWheelEvent(): unexpected mOverflowDeltaX: %f",
    816                             wheelEvent.mOverflowDeltaX);
    817    NS_WARNING(debugMsg.get());
    818  }
    819  if (failedY) {
    820    nsPrintfCString debugMsg("SendWheelEvent(): unexpected mOverflowDeltaY: %f",
    821                             wheelEvent.mOverflowDeltaY);
    822    NS_WARNING(debugMsg.get());
    823  }
    824 #endif
    825 
    826  return (!failedX && !failedY) ? NS_OK : NS_ERROR_FAILURE;
    827 }
    828 
    829 NS_IMETHODIMP
    830 nsDOMWindowUtils::SendTouchEvent(
    831    const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers,
    832    const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs,
    833    const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys,
    834    const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces,
    835    const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs,
    836    const nsTArray<int32_t>& aTwists, int32_t aModifiers,
    837    AsyncEnabledOption aAsyncEnabled, bool* aPreventDefault) {
    838  return SendTouchEventCommon(
    839      aType, aIdentifiers, aXs, aYs, aRxs, aRys, aRotationAngles, aForces,
    840      aTiltXs, aTiltYs, aTwists, aModifiers, /* aIsPen */ false,
    841      /* aToWindow */ false, aAsyncEnabled, aPreventDefault);
    842 }
    843 
    844 NS_IMETHODIMP
    845 nsDOMWindowUtils::SendTouchEventAsPen(
    846    const nsAString& aType, uint32_t aIdentifier, int32_t aX, int32_t aY,
    847    uint32_t aRx, uint32_t aRy, float aRotationAngle, float aForce,
    848    int32_t aTiltX, int32_t aTiltY, int32_t aTwist, int32_t aModifier,
    849    AsyncEnabledOption aAsyncEnabled, bool* aPreventDefault) {
    850  return SendTouchEventCommon(
    851      aType, nsTArray{aIdentifier}, nsTArray{aX}, nsTArray{aY}, nsTArray{aRx},
    852      nsTArray{aRy}, nsTArray{aRotationAngle}, nsTArray{aForce},
    853      nsTArray{aTiltX}, nsTArray{aTiltY}, nsTArray{aTwist}, aModifier,
    854      /* aIsPen */ true, /* aToWindow */ false, aAsyncEnabled, aPreventDefault);
    855 }
    856 
    857 NS_IMETHODIMP
    858 nsDOMWindowUtils::SendTouchEventToWindow(
    859    const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers,
    860    const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs,
    861    const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys,
    862    const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces,
    863    const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs,
    864    const nsTArray<int32_t>& aTwists, int32_t aModifiers,
    865    bool* aPreventDefault) {
    866  return SendTouchEventCommon(
    867      aType, aIdentifiers, aXs, aYs, aRxs, aRys, aRotationAngles, aForces,
    868      aTiltXs, aTiltYs, aTwists, aModifiers, /* aIsPen */ false,
    869      /* aToWindow */ true, AsyncEnabledOption::ASYNC_DISABLED,
    870      aPreventDefault);
    871 }
    872 
    873 nsresult nsDOMWindowUtils::SendTouchEventCommon(
    874    const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers,
    875    const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs,
    876    const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys,
    877    const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces,
    878    const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs,
    879    const nsTArray<int32_t>& aTwists, int32_t aModifiers, bool aIsPen,
    880    bool aToWindow, AsyncEnabledOption aAsyncEnabled, bool* aPreventDefault) {
    881  // get the widget to send the event to
    882  nsPoint offset;
    883  nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
    884  if (!widget) {
    885    return NS_ERROR_NULL_POINTER;
    886  }
    887  EventMessage msg;
    888  if (aType.EqualsLiteral("touchstart")) {
    889    msg = eTouchStart;
    890  } else if (aType.EqualsLiteral("touchmove")) {
    891    msg = eTouchMove;
    892  } else if (aType.EqualsLiteral("touchend")) {
    893    msg = eTouchEnd;
    894  } else if (aType.EqualsLiteral("touchcancel")) {
    895    msg = eTouchCancel;
    896  } else {
    897    return NS_ERROR_UNEXPECTED;
    898  }
    899  WidgetTouchEvent event(true, msg, widget);
    900  event.mFlags.mIsSynthesizedForTests = true;
    901  event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
    902  if (aIsPen) {
    903    event.mInputSource = MouseEvent_Binding::MOZ_SOURCE_PEN;
    904  }
    905 
    906  nsPresContext* presContext = GetPresContext();
    907  if (!presContext) {
    908    return NS_ERROR_FAILURE;
    909  }
    910  uint32_t count = aIdentifiers.Length();
    911  if (aXs.Length() != count || aYs.Length() != count ||
    912      aRxs.Length() != count || aRys.Length() != count ||
    913      aRotationAngles.Length() != count || aForces.Length() != count) {
    914    return NS_ERROR_INVALID_ARG;
    915  }
    916  event.mTouches.SetCapacity(count);
    917  for (uint32_t i = 0; i < count; ++i) {
    918    LayoutDeviceIntPoint pt = nsContentUtils::ToWidgetPoint(
    919        CSSPoint(aXs[i], aYs[i]), offset, presContext);
    920    LayoutDeviceIntPoint radius = LayoutDeviceIntPoint::FromAppUnitsRounded(
    921        CSSPoint::ToAppUnits(CSSPoint(aRxs[i], aRys[i])),
    922        presContext->AppUnitsPerDevPixel());
    923 
    924    RefPtr<Touch> t = new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i],
    925                                aForces[i], aTiltXs[i], aTiltYs[i], aTwists[i]);
    926 
    927    event.mTouches.AppendElement(t);
    928  }
    929 
    930  nsEventStatus status = nsEventStatus_eIgnore;
    931  if (aToWindow) {
    932    RefPtr<PresShell> presShell = presContext->PresShell();
    933    MOZ_TRY(presShell->HandleEvent(presShell->GetRootFrame(), &event, false,
    934                                   &status));
    935  } else if (aAsyncEnabled == AsyncEnabledOption::ASYNC_ENABLED ||
    936             StaticPrefs::test_events_async_enabled()) {
    937    status = widget->DispatchInputEvent(&event).mContentStatus;
    938  } else {
    939    status = widget->DispatchEvent(&event);
    940  }
    941  if (aPreventDefault) {
    942    *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
    943  }
    944  return NS_OK;
    945 }
    946 
    947 static_assert(
    948    static_cast<uint32_t>(nsIWidget::Modifiers::CAPS_LOCK) ==
    949        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CAPS_LOCK),
    950    "Need to sync CapsLock value between nsIWidget::Modifiers and "
    951    "nsIDOMWindowUtils");
    952 static_assert(
    953    static_cast<uint32_t>(nsIWidget::Modifiers::NUM_LOCK) ==
    954        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_NUM_LOCK),
    955    "Need to sync NumLock value between nsIWidget::Modifiers and "
    956    "nsIDOMWindowUtils");
    957 static_assert(
    958    static_cast<uint32_t>(nsIWidget::Modifiers::SHIFT_L) ==
    959        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_SHIFT_LEFT),
    960    "Need to sync ShiftLeft value between nsIWidget::Modifiers and "
    961    "nsIDOMWindowUtils");
    962 static_assert(
    963    static_cast<uint32_t>(nsIWidget::Modifiers::SHIFT_R) ==
    964        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_SHIFT_RIGHT),
    965    "Need to sync ShiftRight value between nsIWidget::Modifiers and "
    966    "nsIDOMWindowUtils");
    967 static_assert(
    968    static_cast<uint32_t>(nsIWidget::Modifiers::CTRL_L) ==
    969        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CONTROL_LEFT),
    970    "Need to sync ControlLeft value between nsIWidget::Modifiers and "
    971    "nsIDOMWindowUtils");
    972 static_assert(
    973    static_cast<uint32_t>(nsIWidget::Modifiers::CTRL_R) ==
    974        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CONTROL_RIGHT),
    975    "Need to sync ControlRight value between nsIWidget::Modifiers "
    976    "and nsIDOMWindowUtils");
    977 static_assert(
    978    static_cast<uint32_t>(nsIWidget::Modifiers::ALT_L) ==
    979        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_LEFT),
    980    "Need to sync AltLeft value between nsIWidget::Modifiers and "
    981    "nsIDOMWindowUtils");
    982 static_assert(
    983    static_cast<uint32_t>(nsIWidget::Modifiers::ALT_R) ==
    984        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_RIGHT),
    985    "Need to sync AltRight value between nsIWidget::Modifiers and "
    986    "nsIDOMWindowUtils");
    987 static_assert(
    988    static_cast<uint32_t>(nsIWidget::Modifiers::COMMAND_L) ==
    989        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_COMMAND_LEFT),
    990    "Need to sync CommandLeft value between nsIWidget::Modifiers and "
    991    "nsIDOMWindowUtils");
    992 static_assert(
    993    static_cast<uint32_t>(nsIWidget::Modifiers::COMMAND_R) ==
    994        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_COMMAND_RIGHT),
    995    "Need to sync CommandRight value between nsIWidget::Modifiers "
    996    "and nsIDOMWindowUtils");
    997 static_assert(
    998    static_cast<uint32_t>(nsIWidget::Modifiers::HELP) ==
    999        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_HELP),
   1000    "Need to sync Help value between nsIWidget::Modifiers and "
   1001    "nsIDOMWindowUtils");
   1002 static_assert(
   1003    static_cast<uint32_t>(nsIWidget::Modifiers::ALTGRAPH) ==
   1004        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_GRAPH),
   1005    "Need to sync AltGraph value between nsIWidget::Modifiers and "
   1006    "nsIDOMWindowUtils");
   1007 static_assert(
   1008    static_cast<uint32_t>(nsIWidget::Modifiers::FUNCTION) ==
   1009        static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_FUNCTION),
   1010    "Need to sync Function value between nsIWidget::Modifiers and "
   1011    "nsIDOMWindowUtils");
   1012 static_assert(static_cast<uint32_t>(nsIWidget::Modifiers::NUMERIC_KEY_PAD) ==
   1013                  static_cast<uint32_t>(
   1014                      nsIDOMWindowUtils::NATIVE_MODIFIER_NUMERIC_KEY_PAD),
   1015              "Need to sync NumericKeyPad value between nsIWidget::Modifiers "
   1016              "and nsIDOMWindowUtils");
   1017 
   1018 static nsIWidget::Modifiers GetWidgetModifiers(uint32_t aNativeModifiers) {
   1019  nsIWidget::Modifiers widgetModifiers = static_cast<nsIWidget::Modifiers>(
   1020      aNativeModifiers &
   1021      (nsIWidget::Modifiers::CAPS_LOCK | nsIWidget::Modifiers::NUM_LOCK |
   1022       nsIWidget::Modifiers::SHIFT_L | nsIWidget::Modifiers::SHIFT_R |
   1023       nsIWidget::Modifiers::CTRL_L | nsIWidget::Modifiers::CTRL_R |
   1024       nsIWidget::Modifiers::ALT_L | nsIWidget::Modifiers::ALT_R |
   1025       nsIWidget::Modifiers::COMMAND_L | nsIWidget::Modifiers::COMMAND_R |
   1026       nsIWidget::Modifiers::HELP | nsIWidget::Modifiers::ALTGRAPH |
   1027       nsIWidget::Modifiers::FUNCTION | nsIWidget::Modifiers::NUMERIC_KEY_PAD));
   1028  NS_ASSERTION(static_cast<uint32_t>(widgetModifiers) == aNativeModifiers,
   1029               "Invalid value is specified to the native modifiers");
   1030  return widgetModifiers;
   1031 }
   1032 
   1033 NS_IMETHODIMP
   1034 nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout,
   1035                                     int32_t aNativeKeyCode,
   1036                                     uint32_t aModifiers,
   1037                                     const nsAString& aCharacters,
   1038                                     const nsAString& aUnmodifiedCharacters,
   1039                                     nsISynthesizedEventCallback* aCallback) {
   1040  // get the widget to send the event to
   1041  nsCOMPtr<nsIWidget> widget = GetWidget();
   1042  if (!widget) {
   1043    return NS_ERROR_FAILURE;
   1044  }
   1045 
   1046  NS_DispatchToMainThread(NativeInputRunnable::Create(
   1047      NewRunnableMethod<int32_t, int32_t, uint32_t, nsString, nsString,
   1048                        nsISynthesizedEventCallback*>(
   1049          "nsIWidget::SynthesizeNativeKeyEvent", widget,
   1050          &nsIWidget::SynthesizeNativeKeyEvent, aNativeKeyboardLayout,
   1051          aNativeKeyCode, static_cast<uint32_t>(GetWidgetModifiers(aModifiers)),
   1052          aCharacters, aUnmodifiedCharacters, aCallback)));
   1053  return NS_OK;
   1054 }
   1055 
   1056 NS_IMETHODIMP
   1057 nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX, int32_t aScreenY,
   1058                                       uint32_t aNativeMessage, int16_t aButton,
   1059                                       uint32_t aModifierFlags,
   1060                                       Element* aElementOnWidget,
   1061                                       nsISynthesizedEventCallback* aCallback) {
   1062  // get the widget to send the event to
   1063  nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElementOnWidget);
   1064  if (!widget) {
   1065    return NS_ERROR_FAILURE;
   1066  }
   1067 
   1068  nsIWidget::NativeMouseMessage message;
   1069  switch (aNativeMessage) {
   1070    case NATIVE_MOUSE_MESSAGE_BUTTON_DOWN:
   1071      message = nsIWidget::NativeMouseMessage::ButtonDown;
   1072      break;
   1073    case NATIVE_MOUSE_MESSAGE_BUTTON_UP:
   1074      message = nsIWidget::NativeMouseMessage::ButtonUp;
   1075      break;
   1076    case NATIVE_MOUSE_MESSAGE_MOVE:
   1077      message = nsIWidget::NativeMouseMessage::Move;
   1078      break;
   1079    case NATIVE_MOUSE_MESSAGE_ENTER_WINDOW:
   1080      message = nsIWidget::NativeMouseMessage::EnterWindow;
   1081      break;
   1082    case NATIVE_MOUSE_MESSAGE_LEAVE_WINDOW:
   1083      message = nsIWidget::NativeMouseMessage::LeaveWindow;
   1084      break;
   1085    default:
   1086      return NS_ERROR_INVALID_ARG;
   1087  }
   1088 
   1089  NS_DispatchToMainThread(NativeInputRunnable::Create(
   1090      NewRunnableMethod<LayoutDeviceIntPoint, nsIWidget::NativeMouseMessage,
   1091                        MouseButton, nsIWidget::Modifiers,
   1092                        nsISynthesizedEventCallback*>(
   1093          "nsIWidget::SynthesizeNativeMouseEvent", widget,
   1094          &nsIWidget::SynthesizeNativeMouseEvent,
   1095          LayoutDeviceIntPoint(aScreenX, aScreenY), message,
   1096          static_cast<MouseButton>(aButton), GetWidgetModifiers(aModifierFlags),
   1097          aCallback)));
   1098  return NS_OK;
   1099 }
   1100 
   1101 NS_IMETHODIMP
   1102 nsDOMWindowUtils::SendNativeMouseScrollEvent(
   1103    int32_t aScreenX, int32_t aScreenY, uint32_t aNativeMessage, double aDeltaX,
   1104    double aDeltaY, double aDeltaZ, uint32_t aModifierFlags,
   1105    uint32_t aAdditionalFlags, Element* aElement,
   1106    nsISynthesizedEventCallback* aCallback) {
   1107  // get the widget to send the event to
   1108  nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement);
   1109  if (!widget) {
   1110    return NS_ERROR_FAILURE;
   1111  }
   1112 
   1113  NS_DispatchToMainThread(NativeInputRunnable::Create(
   1114      NewRunnableMethod<mozilla::LayoutDeviceIntPoint, uint32_t, double, double,
   1115                        double, uint32_t, uint32_t,
   1116                        nsISynthesizedEventCallback*>(
   1117          "nsIWidget::SynthesizeNativeMouseScrollEvent", widget,
   1118          &nsIWidget::SynthesizeNativeMouseScrollEvent,
   1119          LayoutDeviceIntPoint(aScreenX, aScreenY), aNativeMessage, aDeltaX,
   1120          aDeltaY, aDeltaZ, aModifierFlags, aAdditionalFlags, aCallback)));
   1121  return NS_OK;
   1122 }
   1123 
   1124 NS_IMETHODIMP
   1125 nsDOMWindowUtils::SendNativeTouchPoint(uint32_t aPointerId,
   1126                                       uint32_t aTouchState, int32_t aScreenX,
   1127                                       int32_t aScreenY, double aPressure,
   1128                                       uint32_t aOrientation,
   1129                                       nsISynthesizedEventCallback* aCallback,
   1130                                       Element* aElement) {
   1131  // FYI: This was designed for automated tests, but currently, this is used by
   1132  //      DevTools to emulate touch events from mouse events in the responsive
   1133  //      design mode.
   1134 
   1135  nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement);
   1136  if (!widget) {
   1137    return NS_ERROR_FAILURE;
   1138  }
   1139 
   1140  if (aPressure < 0 || aPressure > 1 || aOrientation > 359) {
   1141    return NS_ERROR_INVALID_ARG;
   1142  }
   1143 
   1144  NS_DispatchToMainThread(NativeInputRunnable::Create(
   1145      NewRunnableMethod<uint32_t, nsIWidget::TouchPointerState,
   1146                        LayoutDeviceIntPoint, double, uint32_t,
   1147                        nsISynthesizedEventCallback*>(
   1148          "nsIWidget::SynthesizeNativeTouchPoint", widget,
   1149          &nsIWidget::SynthesizeNativeTouchPoint, aPointerId,
   1150          (nsIWidget::TouchPointerState)aTouchState,
   1151          LayoutDeviceIntPoint(aScreenX, aScreenY), aPressure, aOrientation,
   1152          aCallback)));
   1153  return NS_OK;
   1154 }
   1155 
   1156 NS_IMETHODIMP
   1157 nsDOMWindowUtils::SendNativeTouchpadPinch(uint32_t aEventPhase, float aScale,
   1158                                          int32_t aScreenX, int32_t aScreenY,
   1159                                          int32_t aModifierFlags) {
   1160  nsCOMPtr<nsIWidget> widget = GetWidget();
   1161  if (!widget) {
   1162    return NS_ERROR_FAILURE;
   1163  }
   1164  NS_DispatchToMainThread(NativeInputRunnable::Create(
   1165      NewRunnableMethod<nsIWidget::TouchpadGesturePhase, float,
   1166                        LayoutDeviceIntPoint, int32_t>(
   1167          "nsIWidget::SynthesizeNativeTouchPadPinch", widget,
   1168          &nsIWidget::SynthesizeNativeTouchPadPinch,
   1169          (nsIWidget::TouchpadGesturePhase)aEventPhase, aScale,
   1170          LayoutDeviceIntPoint(aScreenX, aScreenY), aModifierFlags)));
   1171  return NS_OK;
   1172 }
   1173 
   1174 NS_IMETHODIMP
   1175 nsDOMWindowUtils::SendNativeTouchTap(int32_t aScreenX, int32_t aScreenY,
   1176                                     bool aLongTap,
   1177                                     nsISynthesizedEventCallback* aCallback) {
   1178  nsCOMPtr<nsIWidget> widget = GetWidget();
   1179  if (!widget) {
   1180    return NS_ERROR_FAILURE;
   1181  }
   1182 
   1183  NS_DispatchToMainThread(NativeInputRunnable::Create(
   1184      NewRunnableMethod<LayoutDeviceIntPoint, bool,
   1185                        nsISynthesizedEventCallback*>(
   1186          "nsIWidget::SynthesizeNativeTouchTap", widget,
   1187          &nsIWidget::SynthesizeNativeTouchTap,
   1188          LayoutDeviceIntPoint(aScreenX, aScreenY), aLongTap, aCallback)));
   1189  return NS_OK;
   1190 }
   1191 
   1192 NS_IMETHODIMP
   1193 nsDOMWindowUtils::SendNativePenInput(uint32_t aPointerId,
   1194                                     uint32_t aPointerState, int32_t aScreenX,
   1195                                     int32_t aScreenY, double aPressure,
   1196                                     uint32_t aRotation, int32_t aTiltX,
   1197                                     int32_t aTiltY, int32_t aButton,
   1198                                     nsISynthesizedEventCallback* aCallback,
   1199                                     Element* aElement) {
   1200  nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement);
   1201  if (!widget) {
   1202    return NS_ERROR_FAILURE;
   1203  }
   1204 
   1205  if (aPressure < 0 || aPressure > 1 || aRotation > 359 || aTiltX < -90 ||
   1206      aTiltX > 90 || aTiltY < -90 || aTiltY > 90) {
   1207    return NS_ERROR_INVALID_ARG;
   1208  }
   1209 
   1210  NS_DispatchToMainThread(NativeInputRunnable::Create(
   1211      NewRunnableMethod<uint32_t, nsIWidget::TouchPointerState,
   1212                        LayoutDeviceIntPoint, double, uint32_t, int32_t,
   1213                        int32_t, int32_t, nsISynthesizedEventCallback*>(
   1214          "nsIWidget::SynthesizeNativePenInput", widget,
   1215          &nsIWidget::SynthesizeNativePenInput, aPointerId,
   1216          (nsIWidget::TouchPointerState)aPointerState,
   1217          LayoutDeviceIntPoint(aScreenX, aScreenY), aPressure, aRotation,
   1218          aTiltX, aTiltY, aButton, aCallback)));
   1219  return NS_OK;
   1220 }
   1221 
   1222 NS_IMETHODIMP
   1223 nsDOMWindowUtils::SendNativeTouchpadDoubleTap(int32_t aScreenX,
   1224                                              int32_t aScreenY,
   1225                                              int32_t aModifierFlags) {
   1226  nsCOMPtr<nsIWidget> widget = GetWidget();
   1227  if (!widget) {
   1228    return NS_ERROR_FAILURE;
   1229  }
   1230 
   1231  MOZ_ASSERT(aModifierFlags >= 0);
   1232  NS_DispatchToMainThread(NativeInputRunnable::Create(
   1233      NewRunnableMethod<LayoutDeviceIntPoint, uint32_t>(
   1234          "nsIWidget::SynthesizeNativeTouchpadDoubleTap", widget,
   1235          &nsIWidget::SynthesizeNativeTouchpadDoubleTap,
   1236          LayoutDeviceIntPoint(aScreenX, aScreenY), aModifierFlags)));
   1237  return NS_OK;
   1238 }
   1239 
   1240 NS_IMETHODIMP
   1241 nsDOMWindowUtils::SendNativeTouchpadPan(
   1242    uint32_t aEventPhase, int32_t aScreenX, int32_t aScreenY, double aDeltaX,
   1243    double aDeltaY, int32_t aModifierFlags,
   1244    nsISynthesizedEventCallback* aCallback) {
   1245  nsCOMPtr<nsIWidget> widget = GetWidget();
   1246  if (!widget) {
   1247    return NS_ERROR_FAILURE;
   1248  }
   1249 
   1250  MOZ_ASSERT(aModifierFlags >= 0);
   1251  NS_DispatchToMainThread(NativeInputRunnable::Create(
   1252      NewRunnableMethod<nsIWidget::TouchpadGesturePhase, LayoutDeviceIntPoint,
   1253                        double, double, uint32_t, nsISynthesizedEventCallback*>(
   1254          "nsIWidget::SynthesizeNativeTouchpadPan", widget,
   1255          &nsIWidget::SynthesizeNativeTouchpadPan,
   1256          (nsIWidget::TouchpadGesturePhase)aEventPhase,
   1257          LayoutDeviceIntPoint(aScreenX, aScreenY), aDeltaX, aDeltaY,
   1258          aModifierFlags, aCallback)));
   1259  return NS_OK;
   1260 }
   1261 
   1262 NS_IMETHODIMP
   1263 nsDOMWindowUtils::SuppressAnimation(bool aSuppress) {
   1264  nsIWidget* widget = GetWidget();
   1265  if (widget) {
   1266    widget->SuppressAnimation(aSuppress);
   1267  }
   1268  return NS_OK;
   1269 }
   1270 
   1271 NS_IMETHODIMP
   1272 nsDOMWindowUtils::GetParsedStyleSheets(uint32_t* aSheets) {
   1273  RefPtr<Document> doc = GetDocument();
   1274  if (!doc) {
   1275    return NS_ERROR_UNEXPECTED;
   1276  }
   1277  css::Loader* cssLoader = doc->GetExistingCSSLoader();
   1278  if (cssLoader) {
   1279    *aSheets = cssLoader->ParsedSheetCount();
   1280  } else {
   1281    *aSheets = 0;
   1282  }
   1283  return NS_OK;
   1284 }
   1285 
   1286 NS_IMETHODIMP
   1287 nsDOMWindowUtils::ActivateNativeMenuItemAt(const nsAString& indexString) {
   1288  // get the widget to send the event to
   1289  nsCOMPtr<nsIWidget> widget = GetWidget();
   1290  if (!widget) return NS_ERROR_FAILURE;
   1291 
   1292  return widget->ActivateNativeMenuItemAt(indexString);
   1293 }
   1294 
   1295 NS_IMETHODIMP
   1296 nsDOMWindowUtils::ForceUpdateNativeMenuAt(const nsAString& indexString) {
   1297  // get the widget to send the event to
   1298  nsCOMPtr<nsIWidget> widget = GetWidget();
   1299  if (!widget) return NS_ERROR_FAILURE;
   1300 
   1301  return widget->ForceUpdateNativeMenuAt(indexString);
   1302 }
   1303 
   1304 NS_IMETHODIMP
   1305 nsDOMWindowUtils::GetSelectionAsPlaintext(nsAString& aResult) {
   1306  // Get the widget to send the event to.
   1307  nsCOMPtr<nsIWidget> widget = GetWidget();
   1308  if (!widget) {
   1309    return NS_ERROR_FAILURE;
   1310  }
   1311 
   1312  return widget->GetSelectionAsPlaintext(aResult);
   1313 }
   1314 
   1315 nsIWidget* nsDOMWindowUtils::GetWidget(nsPoint* aOffset) {
   1316  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   1317  if (window) {
   1318    nsIDocShell* docShell = window->GetDocShell();
   1319    if (docShell) {
   1320      return nsContentUtils::GetWidget(docShell->GetPresShell(), aOffset);
   1321    }
   1322  }
   1323 
   1324  return nullptr;
   1325 }
   1326 
   1327 nsIWidget* nsDOMWindowUtils::GetWidgetForElement(Element* aElement,
   1328                                                 nsPoint* aOffset) {
   1329  if (!aElement) {
   1330    return GetWidget(aOffset);
   1331  }
   1332  if (Document* doc = aElement->GetUncomposedDoc()) {
   1333    if (PresShell* presShell = doc->GetPresShell()) {
   1334      nsIFrame* frame = aElement->GetPrimaryFrame();
   1335      if (!frame) {
   1336        frame = presShell->GetRootFrame();
   1337      }
   1338      if (frame) {
   1339        nsPoint offset;
   1340        nsIWidget* widget = frame->GetNearestWidget(offset);
   1341        if (aOffset) {
   1342          *aOffset = offset;
   1343        }
   1344        return widget;
   1345      }
   1346    }
   1347  }
   1348 
   1349  return nullptr;
   1350 }
   1351 
   1352 NS_IMETHODIMP
   1353 nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener* aListener) {
   1354  AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GCCC);
   1355 
   1356  nsJSContext::GarbageCollectNow(JS::GCReason::DOM_UTILS);
   1357  nsJSContext::CycleCollectNow(CCReason::API, aListener);
   1358 
   1359  return NS_OK;
   1360 }
   1361 
   1362 NS_IMETHODIMP
   1363 nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener* aListener) {
   1364  nsJSContext::CycleCollectNow(CCReason::API, aListener);
   1365  return NS_OK;
   1366 }
   1367 
   1368 static bool ParseGCReason(const nsACString& aStr, JS::GCReason* aReason,
   1369                          JS::GCReason aDefault) {
   1370  if (aStr.IsEmpty()) {
   1371    *aReason = aDefault;
   1372    return true;
   1373  }
   1374 #define CHECK_REASON(name, _)         \
   1375  if (aStr.EqualsIgnoreCase(#name)) { \
   1376    *aReason = JS::GCReason::name;    \
   1377    return true;                      \
   1378  }
   1379  GCREASONS(CHECK_REASON);
   1380  return false;
   1381 }
   1382 
   1383 NS_IMETHODIMP
   1384 nsDOMWindowUtils::RunNextCollectorTimer(const nsACString& aReason) {
   1385  JS::GCReason reason;
   1386  if (!ParseGCReason(aReason, &reason, JS::GCReason::DOM_WINDOW_UTILS)) {
   1387    return NS_ERROR_INVALID_ARG;
   1388  }
   1389 
   1390  nsJSContext::RunNextCollectorTimer(reason);
   1391 
   1392  return NS_OK;
   1393 }
   1394 
   1395 NS_IMETHODIMP
   1396 nsDOMWindowUtils::PokeGC(const nsACString& aReason) {
   1397  JS::GCReason reason;
   1398  if (!ParseGCReason(aReason, &reason, JS::GCReason::DOM_WINDOW_UTILS)) {
   1399    return NS_ERROR_INVALID_ARG;
   1400  }
   1401 
   1402  nsJSContext::PokeGC(reason, nullptr);
   1403 
   1404  return NS_OK;
   1405 }
   1406 
   1407 NS_IMETHODIMP
   1408 nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType, float aX,
   1409                                         float aY, uint32_t aDirection,
   1410                                         double aDelta, int32_t aModifiers,
   1411                                         uint32_t aClickCount) {
   1412  // get the widget to send the event to
   1413  nsPoint offset;
   1414  nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
   1415  if (!widget) return NS_ERROR_FAILURE;
   1416 
   1417  EventMessage msg;
   1418  if (aType.EqualsLiteral("MozSwipeGestureMayStart")) {
   1419    msg = eSwipeGestureMayStart;
   1420  } else if (aType.EqualsLiteral("MozSwipeGestureStart")) {
   1421    msg = eSwipeGestureStart;
   1422  } else if (aType.EqualsLiteral("MozSwipeGestureUpdate")) {
   1423    msg = eSwipeGestureUpdate;
   1424  } else if (aType.EqualsLiteral("MozSwipeGestureEnd")) {
   1425    msg = eSwipeGestureEnd;
   1426  } else if (aType.EqualsLiteral("MozSwipeGesture")) {
   1427    msg = eSwipeGesture;
   1428  } else if (aType.EqualsLiteral("MozMagnifyGestureStart")) {
   1429    msg = eMagnifyGestureStart;
   1430  } else if (aType.EqualsLiteral("MozMagnifyGestureUpdate")) {
   1431    msg = eMagnifyGestureUpdate;
   1432  } else if (aType.EqualsLiteral("MozMagnifyGesture")) {
   1433    msg = eMagnifyGesture;
   1434  } else if (aType.EqualsLiteral("MozRotateGestureStart")) {
   1435    msg = eRotateGestureStart;
   1436  } else if (aType.EqualsLiteral("MozRotateGestureUpdate")) {
   1437    msg = eRotateGestureUpdate;
   1438  } else if (aType.EqualsLiteral("MozRotateGesture")) {
   1439    msg = eRotateGesture;
   1440  } else if (aType.EqualsLiteral("MozTapGesture")) {
   1441    msg = eTapGesture;
   1442  } else if (aType.EqualsLiteral("MozPressTapGesture")) {
   1443    msg = ePressTapGesture;
   1444  } else if (aType.EqualsLiteral("MozEdgeUIStarted")) {
   1445    msg = eEdgeUIStarted;
   1446  } else if (aType.EqualsLiteral("MozEdgeUICanceled")) {
   1447    msg = eEdgeUICanceled;
   1448  } else if (aType.EqualsLiteral("MozEdgeUICompleted")) {
   1449    msg = eEdgeUICompleted;
   1450  } else {
   1451    return NS_ERROR_FAILURE;
   1452  }
   1453 
   1454  WidgetSimpleGestureEvent event(true, msg, widget);
   1455  event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
   1456  event.mDirection = aDirection;
   1457  event.mDelta = aDelta;
   1458  event.mClickCount = aClickCount;
   1459 
   1460  nsPresContext* presContext = GetPresContext();
   1461  if (!presContext) return NS_ERROR_FAILURE;
   1462 
   1463  event.mRefPoint =
   1464      nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
   1465 
   1466  widget->DispatchEvent(&event);
   1467  return NS_OK;
   1468 }
   1469 
   1470 NS_IMETHODIMP
   1471 nsDOMWindowUtils::ElementFromPoint(float aX, float aY,
   1472                                   bool aIgnoreRootScrollFrame,
   1473                                   bool aFlushLayout, Element** aReturn) {
   1474  nsCOMPtr<Document> doc = GetDocument();
   1475  NS_ENSURE_STATE(doc);
   1476 
   1477  RefPtr<Element> el = doc->ElementFromPointHelper(
   1478      aX, aY, aIgnoreRootScrollFrame, aFlushLayout, ViewportType::Layout);
   1479  el.forget(aReturn);
   1480  return NS_OK;
   1481 }
   1482 
   1483 NS_IMETHODIMP
   1484 nsDOMWindowUtils::NodesFromRect(float aX, float aY, float aTopSize,
   1485                                float aRightSize, float aBottomSize,
   1486                                float aLeftSize, bool aIgnoreRootScrollFrame,
   1487                                bool aFlushLayout, bool aOnlyVisible,
   1488                                float aVisibleThreshold,
   1489                                nsINodeList** aReturn) {
   1490  RefPtr<Document> doc = GetDocument();
   1491  NS_ENSURE_STATE(doc);
   1492 
   1493  auto list = MakeRefPtr<nsSimpleContentList>(doc);
   1494 
   1495  // The visible threshold was omitted or given a zero value (which makes no
   1496  // sense), so give a reasonable default.
   1497  if (aVisibleThreshold == 0.0f) {
   1498    aVisibleThreshold = 1.0f;
   1499  }
   1500 
   1501  AutoTArray<RefPtr<nsINode>, 8> nodes;
   1502  doc->NodesFromRect(aX, aY, aTopSize, aRightSize, aBottomSize, aLeftSize,
   1503                     aIgnoreRootScrollFrame, aFlushLayout, aOnlyVisible,
   1504                     aVisibleThreshold, nodes);
   1505  list->SetCapacity(nodes.Length());
   1506  for (auto& node : nodes) {
   1507    list->AppendElement(node->AsContent());
   1508  }
   1509 
   1510  list.forget(aReturn);
   1511  return NS_OK;
   1512 }
   1513 
   1514 NS_IMETHODIMP
   1515 nsDOMWindowUtils::GetTranslationNodes(nsINode* aRoot,
   1516                                      nsITranslationNodeList** aRetVal) {
   1517  NS_ENSURE_ARG_POINTER(aRetVal);
   1518  nsCOMPtr<nsIContent> root = do_QueryInterface(aRoot);
   1519  NS_ENSURE_STATE(root);
   1520  nsCOMPtr<Document> doc = GetDocument();
   1521  NS_ENSURE_STATE(doc);
   1522 
   1523  if (root->OwnerDoc() != doc) {
   1524    return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
   1525  }
   1526 
   1527  nsTHashSet<nsIContent*> translationNodesHash(500);
   1528  RefPtr<nsTranslationNodeList> list = new nsTranslationNodeList;
   1529 
   1530  uint32_t limit = 15000;
   1531 
   1532  // We begin iteration with content->GetNextNode because we want to explicitly
   1533  // skip the root tag from being a translation node.
   1534  nsIContent* content = root;
   1535  while ((limit > 0) && (content = content->GetNextNode(root))) {
   1536    if (!content->IsHTMLElement()) {
   1537      continue;
   1538    }
   1539 
   1540    // Skip elements that usually contain non-translatable text content.
   1541    if (content->IsAnyOfHTMLElements(nsGkAtoms::script, nsGkAtoms::iframe,
   1542                                     nsGkAtoms::frameset, nsGkAtoms::frame,
   1543                                     nsGkAtoms::code, nsGkAtoms::noscript,
   1544                                     nsGkAtoms::style)) {
   1545      continue;
   1546    }
   1547 
   1548    // An element is a translation node if it contains
   1549    // at least one text node that has meaningful data
   1550    // for translation
   1551    for (nsIContent* child = content->GetFirstChild(); child;
   1552         child = child->GetNextSibling()) {
   1553      if (child->IsText() && child->GetAsText()->HasTextForTranslation()) {
   1554        translationNodesHash.Insert(content);
   1555 
   1556        nsIFrame* frame = content->GetPrimaryFrame();
   1557        bool isTranslationRoot = frame && frame->IsBlockFrameOrSubclass();
   1558        if (!isTranslationRoot) {
   1559          // If an element is not a block element, it still
   1560          // can be considered a translation root if the parent
   1561          // of this element didn't make into the list of nodes
   1562          // to be translated.
   1563          bool parentInList = false;
   1564          nsIContent* parent = content->GetParent();
   1565          if (parent) {
   1566            parentInList = translationNodesHash.Contains(parent);
   1567          }
   1568          isTranslationRoot = !parentInList;
   1569        }
   1570 
   1571        list->AppendElement(content, isTranslationRoot);
   1572        --limit;
   1573        break;
   1574      }
   1575    }
   1576  }
   1577 
   1578  *aRetVal = list.forget().take();
   1579  return NS_OK;
   1580 }
   1581 
   1582 static already_AddRefed<DataSourceSurface> CanvasToDataSourceSurface(
   1583    HTMLCanvasElement* aCanvas) {
   1584  MOZ_ASSERT(aCanvas);
   1585  SurfaceFromElementResult result = nsLayoutUtils::SurfaceFromElement(aCanvas);
   1586  const RefPtr<SourceSurface> surf = result.GetSourceSurface();
   1587  if (!surf) {
   1588    return nullptr;
   1589  }
   1590  return surf->GetDataSurface();
   1591 }
   1592 
   1593 NS_IMETHODIMP
   1594 nsDOMWindowUtils::CompareCanvases(nsISupports* aCanvas1, nsISupports* aCanvas2,
   1595                                  uint32_t* aMaxDifference, uint32_t* retVal) {
   1596  nsCOMPtr<nsIContent> contentCanvas1 = do_QueryInterface(aCanvas1);
   1597  nsCOMPtr<nsIContent> contentCanvas2 = do_QueryInterface(aCanvas2);
   1598  auto* canvas1 = HTMLCanvasElement::FromNodeOrNull(contentCanvas1);
   1599  auto* canvas2 = HTMLCanvasElement::FromNodeOrNull(contentCanvas2);
   1600 
   1601  if (NS_WARN_IF(!canvas1) || NS_WARN_IF(!canvas2)) {
   1602    return NS_ERROR_FAILURE;
   1603  }
   1604 
   1605  RefPtr<DataSourceSurface> img1 = CanvasToDataSourceSurface(canvas1);
   1606  RefPtr<DataSourceSurface> img2 = CanvasToDataSourceSurface(canvas2);
   1607 
   1608  if (NS_WARN_IF(!img1) || NS_WARN_IF(!img2) ||
   1609      NS_WARN_IF(img1->GetSize() != img2->GetSize())) {
   1610    return NS_ERROR_FAILURE;
   1611  }
   1612 
   1613  if (img1->Equals(img2)) {
   1614    // They point to the same underlying content.
   1615    return NS_OK;
   1616  }
   1617 
   1618  DataSourceSurface::ScopedMap map1(img1, DataSourceSurface::READ);
   1619  DataSourceSurface::ScopedMap map2(img2, DataSourceSurface::READ);
   1620 
   1621  if (NS_WARN_IF(!map1.IsMapped()) || NS_WARN_IF(!map2.IsMapped())) {
   1622    return NS_ERROR_FAILURE;
   1623  }
   1624 
   1625  int v;
   1626  IntSize size = img1->GetSize();
   1627  int32_t stride1 = map1.GetStride();
   1628  int32_t stride2 = map2.GetStride();
   1629 
   1630  // we can optimize for the common all-pass case
   1631  if (stride1 == stride2 && stride1 == size.width * 4) {
   1632    v = memcmp(map1.GetData(), map2.GetData(), size.width * size.height * 4);
   1633    if (v == 0) {
   1634      if (aMaxDifference) *aMaxDifference = 0;
   1635      *retVal = 0;
   1636      return NS_OK;
   1637    }
   1638  }
   1639 
   1640  uint32_t dc = 0;
   1641  uint32_t different = 0;
   1642 
   1643  for (int j = 0; j < size.height; j++) {
   1644    unsigned char* p1 = map1.GetData() + j * stride1;
   1645    unsigned char* p2 = map2.GetData() + j * stride2;
   1646    v = memcmp(p1, p2, size.width * 4);
   1647 
   1648    if (v) {
   1649      for (int i = 0; i < size.width; i++) {
   1650        if (*(uint32_t*)p1 != *(uint32_t*)p2) {
   1651          different++;
   1652 
   1653          dc = std::max((uint32_t)abs(p1[0] - p2[0]), dc);
   1654          dc = std::max((uint32_t)abs(p1[1] - p2[1]), dc);
   1655          dc = std::max((uint32_t)abs(p1[2] - p2[2]), dc);
   1656          dc = std::max((uint32_t)abs(p1[3] - p2[3]), dc);
   1657        }
   1658 
   1659        p1 += 4;
   1660        p2 += 4;
   1661      }
   1662    }
   1663  }
   1664 
   1665  if (aMaxDifference) *aMaxDifference = dc;
   1666 
   1667  *retVal = different;
   1668  return NS_OK;
   1669 }
   1670 
   1671 NS_IMETHODIMP
   1672 nsDOMWindowUtils::GetIsMozAfterPaintPending(bool* aResult) {
   1673  NS_ENSURE_ARG_POINTER(aResult);
   1674  *aResult = false;
   1675  nsPresContext* presContext = GetPresContext();
   1676  if (!presContext) return NS_OK;
   1677  *aResult = presContext->IsDOMPaintEventPending();
   1678  return NS_OK;
   1679 }
   1680 
   1681 NS_IMETHODIMP
   1682 nsDOMWindowUtils::GetIsWindowFullyOccluded(bool* aResult) {
   1683  NS_ENSURE_ARG_POINTER(aResult);
   1684  *aResult = false;
   1685  if (nsIWidget* widget = GetWidget()) {
   1686    *aResult = widget->IsFullyOccluded();
   1687  }
   1688  return NS_OK;
   1689 }
   1690 
   1691 NS_IMETHODIMP
   1692 nsDOMWindowUtils::GetIsCompositorPaused(bool* aResult) {
   1693  NS_ENSURE_ARG_POINTER(aResult);
   1694  *aResult = false;
   1695  CompositorBridgeChild* cbc = GetCompositorBridge();
   1696  if (cbc) {
   1697    *aResult = cbc->IsPaused();
   1698  }
   1699  return NS_OK;
   1700 }
   1701 
   1702 NS_IMETHODIMP
   1703 nsDOMWindowUtils::GetIsInputTaskManagerSuspended(bool* aResult) {
   1704  *aResult = InputTaskManager::Get()->IsSuspended();
   1705  return NS_OK;
   1706 }
   1707 
   1708 NS_IMETHODIMP
   1709 nsDOMWindowUtils::DisableNonTestMouseEvents(bool aDisable) {
   1710  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   1711  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   1712  nsIDocShell* docShell = window->GetDocShell();
   1713  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
   1714  PresShell* presShell = docShell->GetPresShell();
   1715  NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
   1716  presShell->DisableNonTestMouseEvents(aDisable);
   1717  return NS_OK;
   1718 }
   1719 
   1720 NS_IMETHODIMP
   1721 nsDOMWindowUtils::SuppressEventHandling(bool aSuppress) {
   1722  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   1723  NS_ENSURE_STATE(window);
   1724 
   1725  if (aSuppress) {
   1726    window->SuppressEventHandling();
   1727  } else {
   1728    window->UnsuppressEventHandling();
   1729  }
   1730 
   1731  return NS_OK;
   1732 }
   1733 
   1734 static nsresult getScrollXYAppUnits(const nsWeakPtr& aWindow, bool aFlushLayout,
   1735                                    nsPoint& aScrollPos) {
   1736  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(aWindow);
   1737  nsCOMPtr<Document> doc = window ? window->GetExtantDoc() : nullptr;
   1738  NS_ENSURE_STATE(doc);
   1739 
   1740  if (aFlushLayout) {
   1741    doc->FlushPendingNotifications(FlushType::Layout);
   1742  }
   1743 
   1744  if (PresShell* presShell = doc->GetPresShell()) {
   1745    ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame();
   1746    if (sf) {
   1747      aScrollPos = sf->GetScrollPosition();
   1748    }
   1749  }
   1750  return NS_OK;
   1751 }
   1752 
   1753 NS_IMETHODIMP
   1754 nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX,
   1755                              int32_t* aScrollY) {
   1756  nsPoint scrollPos(0, 0);
   1757  nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos);
   1758  NS_ENSURE_SUCCESS(rv, rv);
   1759  *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
   1760  *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
   1761 
   1762  return NS_OK;
   1763 }
   1764 
   1765 NS_IMETHODIMP
   1766 nsDOMWindowUtils::GetScrollXYFloat(bool aFlushLayout, float* aScrollX,
   1767                                   float* aScrollY) {
   1768  nsPoint scrollPos(0, 0);
   1769  nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos);
   1770  NS_ENSURE_SUCCESS(rv, rv);
   1771  *aScrollX = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.x);
   1772  *aScrollY = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.y);
   1773 
   1774  return NS_OK;
   1775 }
   1776 
   1777 NS_IMETHODIMP
   1778 nsDOMWindowUtils::ScrollToVisual(float aOffsetX, float aOffsetY,
   1779                                 int32_t aUpdateType, int32_t aScrollMode) {
   1780  nsCOMPtr<Document> doc = GetDocument();
   1781  NS_ENSURE_STATE(doc);
   1782 
   1783  nsPresContext* presContext = doc->GetPresContext();
   1784  NS_ENSURE_TRUE(presContext, NS_ERROR_NOT_AVAILABLE);
   1785 
   1786  // This should only be called on the root content document.
   1787  NS_ENSURE_TRUE(presContext->IsRootContentDocumentCrossProcess(),
   1788                 NS_ERROR_INVALID_ARG);
   1789 
   1790  ScrollContainerFrame* sf =
   1791      presContext->PresShell()->GetRootScrollContainerFrame();
   1792  NS_ENSURE_TRUE(sf, NS_ERROR_NOT_AVAILABLE);
   1793 
   1794  FrameMetrics::ScrollOffsetUpdateType updateType;
   1795  switch (aUpdateType) {
   1796    case UPDATE_TYPE_RESTORE:
   1797      updateType = FrameMetrics::eRestore;
   1798      break;
   1799    case UPDATE_TYPE_MAIN_THREAD:
   1800      updateType = FrameMetrics::eMainThread;
   1801      break;
   1802    default:
   1803      return NS_ERROR_INVALID_ARG;
   1804  }
   1805 
   1806  ScrollBehavior scrollBehavior;
   1807  switch (aScrollMode) {
   1808    case SCROLL_MODE_INSTANT:
   1809      scrollBehavior = ScrollBehavior::Instant;
   1810      break;
   1811    case SCROLL_MODE_SMOOTH:
   1812      scrollBehavior = ScrollBehavior::Smooth;
   1813      break;
   1814    default:
   1815      return NS_ERROR_INVALID_ARG;
   1816  }
   1817 
   1818  presContext->PresShell()->ScrollToVisual(
   1819      CSSPoint::ToAppUnits(CSSPoint(aOffsetX, aOffsetY)), updateType,
   1820      sf->ScrollModeForScrollBehavior(scrollBehavior));
   1821 
   1822  return NS_OK;
   1823 }
   1824 
   1825 NS_IMETHODIMP
   1826 nsDOMWindowUtils::GetVisualViewportOffsetRelativeToLayoutViewport(
   1827    float* aOffsetX, float* aOffsetY) {
   1828  *aOffsetX = 0;
   1829  *aOffsetY = 0;
   1830 
   1831  nsCOMPtr<Document> doc = GetDocument();
   1832  NS_ENSURE_STATE(doc);
   1833 
   1834  PresShell* presShell = doc->GetPresShell();
   1835  NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
   1836 
   1837  nsPoint offset = presShell->GetVisualViewportOffsetRelativeToLayoutViewport();
   1838  *aOffsetX = nsPresContext::AppUnitsToFloatCSSPixels(offset.x);
   1839  *aOffsetY = nsPresContext::AppUnitsToFloatCSSPixels(offset.y);
   1840 
   1841  return NS_OK;
   1842 }
   1843 
   1844 NS_IMETHODIMP
   1845 nsDOMWindowUtils::GetVisualViewportOffset(int32_t* aOffsetX,
   1846                                          int32_t* aOffsetY) {
   1847  *aOffsetX = 0;
   1848  *aOffsetY = 0;
   1849 
   1850  nsCOMPtr<Document> doc = GetDocument();
   1851  NS_ENSURE_STATE(doc);
   1852 
   1853  PresShell* presShell = doc->GetPresShell();
   1854  NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
   1855 
   1856  nsPoint offset = presShell->GetVisualViewportOffset();
   1857  *aOffsetX = nsPresContext::AppUnitsToIntCSSPixels(offset.x);
   1858  *aOffsetY = nsPresContext::AppUnitsToIntCSSPixels(offset.y);
   1859 
   1860  return NS_OK;
   1861 }
   1862 
   1863 NS_IMETHODIMP
   1864 nsDOMWindowUtils::TransformRectLayoutToVisual(float aX, float aY, float aWidth,
   1865                                              float aHeight,
   1866                                              DOMRect** aResult) {
   1867  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   1868  NS_ENSURE_STATE(window);
   1869 
   1870  PresShell* presShell = GetPresShell();
   1871  NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
   1872 
   1873  CSSRect rect(aX, aY, aWidth, aHeight);
   1874  rect = ViewportUtils::DocumentRelativeLayoutToVisual(rect, presShell);
   1875 
   1876  RefPtr<DOMRect> outRect = new DOMRect(window);
   1877  outRect->SetRect(rect.x, rect.y, rect.width, rect.height);
   1878  outRect.forget(aResult);
   1879  return NS_OK;
   1880 }
   1881 
   1882 Result<mozilla::LayoutDeviceRect, nsresult> nsDOMWindowUtils::ConvertTo(
   1883    float aX, float aY, float aWidth, float aHeight, CoordsType aCoordsType) {
   1884  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   1885  if (!window) {
   1886    return Err(NS_ERROR_NOT_AVAILABLE);
   1887  }
   1888 
   1889  PresShell* presShell = GetPresShell();
   1890  if (!presShell) {
   1891    return Err(NS_ERROR_NOT_AVAILABLE);
   1892  }
   1893 
   1894  nsCOMPtr<nsIWidget> widget = GetWidget();
   1895  if (!widget) {
   1896    return Err(NS_ERROR_NOT_AVAILABLE);
   1897  }
   1898 
   1899  // Note that if the document is NOT in OOP iframes, i.e. it's in the top level
   1900  // content subtree in the same process,
   1901  // nsIWidget::WidgetToTopLevelWidgetTransform() doesn't include the desktop
   1902  // zoom value, so for documents in the top level content document subtree,
   1903  // this ViewportUtils::DocumentRelativeLayoutToVisual call applies the desktop
   1904  // zoom value via PresShell::GetResolution() in the function.
   1905  CSSRect rect(aX, aY, aWidth, aHeight);
   1906  rect = ViewportUtils::DocumentRelativeLayoutToVisual(rect, presShell);
   1907 
   1908  nsPresContext* presContext = presShell->GetPresContext();
   1909  MOZ_ASSERT(presContext);
   1910 
   1911  // For OOP iframe documents, we don't have desktop zoom value specifically in
   1912  // each iframe documents (i.e. the in-process root presshell's resolution is
   1913  // 1.0), instead nsIWidget::WidgetToTopLevelWidgetTransform() includes the
   1914  // desktop zoom scale value along with translations by ancestor scroll
   1915  // containers, ancestor CSS transforms, etc.
   1916  nsRect appUnitsRect = CSSPixel::ToAppUnits(rect);
   1917  LayoutDeviceRect devPixelsRect = LayoutDeviceRect::FromAppUnits(
   1918      appUnitsRect, presContext->AppUnitsPerDevPixel());
   1919  devPixelsRect =
   1920      widget->WidgetToTopLevelWidgetTransform().TransformBounds(devPixelsRect);
   1921 
   1922  switch (aCoordsType) {
   1923    case CoordsType::Screen:
   1924      devPixelsRect += widget->TopLevelWidgetToScreenOffset();
   1925      break;
   1926    case CoordsType::TopLevelWidget:
   1927      // There's nothing to do.
   1928      break;
   1929  }
   1930  return devPixelsRect;
   1931 }
   1932 
   1933 NS_IMETHODIMP
   1934 nsDOMWindowUtils::ToScreenRectInCSSUnits(float aX, float aY, float aWidth,
   1935                                         float aHeight, DOMRect** aResult) {
   1936  LayoutDeviceRect devRect =
   1937      MOZ_TRY(ConvertTo(aX, aY, aWidth, aHeight, CoordsType::Screen));
   1938 
   1939  nsPresContext* presContext = GetPresContext();
   1940  MOZ_ASSERT(presContext);
   1941 
   1942  // We want to return the screen rect in CSS units of the browser chrome.
   1943  //
   1944  // TODO(emilio): It'd be cleaner to convert callers to use plain toScreenRect,
   1945  // and perform the screen -> CSS rect in the parent process instead, probably.
   1946  const nsRect appUnitsRect = LayoutDeviceRect::ToAppUnits(
   1947      devRect,
   1948      presContext->DeviceContext()->AppUnitsPerDevPixelInTopLevelChromePage());
   1949 
   1950  RefPtr<DOMRect> outRect = new DOMRect(mWindow);
   1951  outRect->SetLayoutRect(appUnitsRect);
   1952 
   1953  outRect.forget(aResult);
   1954  return NS_OK;
   1955 }
   1956 
   1957 NS_IMETHODIMP
   1958 nsDOMWindowUtils::ToScreenRect(float aX, float aY, float aWidth, float aHeight,
   1959                               DOMRect** aResult) {
   1960  LayoutDeviceRect devPixelsRect =
   1961      MOZ_TRY(ConvertTo(aX, aY, aWidth, aHeight, CoordsType::Screen));
   1962 
   1963  ScreenRect rect = ViewAs<ScreenPixel>(
   1964      devPixelsRect, PixelCastJustification::ScreenIsParentLayerForRoot);
   1965 
   1966  RefPtr<DOMRect> outRect = new DOMRect(mWindow);
   1967  outRect->SetRect(rect.x, rect.y, rect.width, rect.height);
   1968  outRect.forget(aResult);
   1969  return NS_OK;
   1970 }
   1971 
   1972 NS_IMETHODIMP
   1973 nsDOMWindowUtils::ToTopLevelWidgetRect(float aX, float aY, float aWidth,
   1974                                       float aHeight, DOMRect** aResult) {
   1975  LayoutDeviceRect rect =
   1976      MOZ_TRY(ConvertTo(aX, aY, aWidth, aHeight, CoordsType::TopLevelWidget));
   1977 
   1978  RefPtr<DOMRect> outRect = new DOMRect(mWindow);
   1979  outRect->SetRect(rect.x, rect.y, rect.width, rect.height);
   1980  outRect.forget(aResult);
   1981  return NS_OK;
   1982 }
   1983 
   1984 NS_IMETHODIMP
   1985 nsDOMWindowUtils::ConvertFromParentProcessWidgetToLocal(float aX, float aY,
   1986                                                        float aWidth,
   1987                                                        float aHeight,
   1988                                                        DOMRect** aResult) {
   1989  if (!XRE_IsContentProcess()) {
   1990    return NS_ERROR_NOT_AVAILABLE;
   1991  }
   1992 
   1993  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   1994  if (!window) {
   1995    return NS_ERROR_NOT_AVAILABLE;
   1996  }
   1997 
   1998  nsCOMPtr<nsIWidget> widget = GetWidget();
   1999  if (!widget) {
   2000    return NS_ERROR_NOT_AVAILABLE;
   2001  }
   2002 
   2003  LayoutDeviceRect devPixelsRect = LayoutDeviceRect(aX, aY, aWidth, aHeight);
   2004 
   2005  Maybe<LayoutDeviceToLayoutDeviceMatrix4x4> inverse =
   2006      widget->WidgetToTopLevelWidgetTransform().MaybeInverse();
   2007  if (inverse) {
   2008    Maybe<LayoutDeviceRect> rect =
   2009        UntransformBy(*inverse, devPixelsRect, LayoutDeviceRect::MaxIntRect());
   2010    if (rect) {
   2011      RefPtr<DOMRect> outRect = new DOMRect(mWindow);
   2012      outRect->SetRect(rect->x, rect->y, rect->width, rect->height);
   2013      outRect.forget(aResult);
   2014      return NS_OK;
   2015    }
   2016  }
   2017 
   2018  RefPtr<DOMRect> outRect = new DOMRect(mWindow);
   2019  outRect->SetRect(0, 0, 0, 0);
   2020  outRect.forget(aResult);
   2021  return NS_ERROR_NOT_AVAILABLE;
   2022 }
   2023 
   2024 NS_IMETHODIMP
   2025 nsDOMWindowUtils::SetDynamicToolbarMaxHeight(uint32_t aHeightInScreen) {
   2026  if (aHeightInScreen > INT32_MAX) {
   2027    return NS_ERROR_INVALID_ARG;
   2028  }
   2029 
   2030  RefPtr<nsPresContext> presContext = GetPresContext();
   2031  if (!presContext) {
   2032    return NS_OK;
   2033  }
   2034 
   2035  MOZ_ASSERT(presContext->IsRootContentDocumentCrossProcess());
   2036 
   2037  presContext->SetDynamicToolbarMaxHeight(ScreenIntCoord(aHeightInScreen));
   2038 
   2039  return NS_OK;
   2040 }
   2041 
   2042 NS_IMETHODIMP
   2043 nsDOMWindowUtils::GetScrollbarSize(bool aFlushLayout, int32_t* aWidth,
   2044                                   int32_t* aHeight) {
   2045  *aWidth = 0;
   2046  *aHeight = 0;
   2047 
   2048  nsCOMPtr<Document> doc = GetDocument();
   2049  NS_ENSURE_STATE(doc);
   2050 
   2051  if (aFlushLayout) {
   2052    doc->FlushPendingNotifications(FlushType::Layout);
   2053  }
   2054 
   2055  PresShell* presShell = doc->GetPresShell();
   2056  NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
   2057 
   2058  ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame();
   2059  NS_ENSURE_TRUE(sf, NS_OK);
   2060 
   2061  nsMargin sizes = sf->GetActualScrollbarSizes();
   2062  *aWidth = nsPresContext::AppUnitsToIntCSSPixels(sizes.LeftRight());
   2063  *aHeight = nsPresContext::AppUnitsToIntCSSPixels(sizes.TopBottom());
   2064 
   2065  return NS_OK;
   2066 }
   2067 
   2068 NS_IMETHODIMP
   2069 nsDOMWindowUtils::GetBoundsWithoutFlushing(Element* aElement,
   2070                                           DOMRect** aResult) {
   2071  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2072  NS_ENSURE_STATE(window);
   2073 
   2074  NS_ENSURE_ARG_POINTER(aElement);
   2075 
   2076  RefPtr<DOMRect> rect = new DOMRect(window);
   2077  nsIFrame* frame = aElement->GetPrimaryFrame();
   2078 
   2079  if (frame) {
   2080    nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(
   2081        frame, nsLayoutUtils::GetContainingBlockForClientRect(frame),
   2082        nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms);
   2083    rect->SetLayoutRect(r);
   2084  }
   2085 
   2086  rect.forget(aResult);
   2087  return NS_OK;
   2088 }
   2089 
   2090 NS_IMETHODIMP
   2091 nsDOMWindowUtils::NeedsFlush(int32_t aFlushType, bool* aResult) {
   2092  MOZ_ASSERT(aResult);
   2093 
   2094  nsCOMPtr<Document> doc = GetDocument();
   2095  NS_ENSURE_STATE(doc);
   2096 
   2097  PresShell* presShell = doc->GetPresShell();
   2098  NS_ENSURE_STATE(presShell);
   2099 
   2100  FlushType flushType;
   2101  switch (aFlushType) {
   2102    case FLUSH_STYLE:
   2103      flushType = FlushType::Style;
   2104      break;
   2105 
   2106    case FLUSH_LAYOUT:
   2107      flushType = FlushType::Layout;
   2108      break;
   2109 
   2110    default:
   2111      return NS_ERROR_INVALID_ARG;
   2112  }
   2113 
   2114  *aResult = presShell->NeedFlush(flushType);
   2115  return NS_OK;
   2116 }
   2117 
   2118 NS_IMETHODIMP
   2119 nsDOMWindowUtils::FlushLayoutWithoutThrottledAnimations() {
   2120  if (nsCOMPtr<Document> doc = GetDocument()) {
   2121    doc->FlushPendingNotifications(
   2122        ChangesToFlush(FlushType::Layout, /* aFlushAnimations = */ false,
   2123                       /* aUpdateRelevancy = */ true));
   2124  }
   2125  return NS_OK;
   2126 }
   2127 
   2128 NS_IMETHODIMP
   2129 nsDOMWindowUtils::GetRootBounds(DOMRect** aResult) {
   2130  Document* doc = GetDocument();
   2131  NS_ENSURE_STATE(doc);
   2132 
   2133  nsRect bounds(0, 0, 0, 0);
   2134  PresShell* presShell = doc->GetPresShell();
   2135  if (presShell) {
   2136    ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame();
   2137    if (sf) {
   2138      bounds = sf->GetScrollRange();
   2139      bounds.SetWidth(bounds.Width() + sf->GetScrollPortRect().Width());
   2140      bounds.SetHeight(bounds.Height() + sf->GetScrollPortRect().Height());
   2141    } else if (presShell->GetRootFrame()) {
   2142      bounds = presShell->GetRootFrame()->GetRect();
   2143    }
   2144  }
   2145 
   2146  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2147  RefPtr<DOMRect> rect = new DOMRect(window);
   2148  rect->SetRect(nsPresContext::AppUnitsToFloatCSSPixels(bounds.x),
   2149                nsPresContext::AppUnitsToFloatCSSPixels(bounds.y),
   2150                nsPresContext::AppUnitsToFloatCSSPixels(bounds.Width()),
   2151                nsPresContext::AppUnitsToFloatCSSPixels(bounds.Height()));
   2152  rect.forget(aResult);
   2153  return NS_OK;
   2154 }
   2155 
   2156 NS_IMETHODIMP
   2157 nsDOMWindowUtils::GetIMEIsOpen(bool* aState) {
   2158  NS_ENSURE_ARG_POINTER(aState);
   2159 
   2160  nsCOMPtr<nsIWidget> widget = GetWidget();
   2161  if (!widget) return NS_ERROR_FAILURE;
   2162 
   2163  // Open state should not be available when IME is not enabled.
   2164  InputContext context = widget->GetInputContext();
   2165  if (context.mIMEState.mEnabled != IMEEnabled::Enabled) {
   2166    return NS_ERROR_NOT_AVAILABLE;
   2167  }
   2168 
   2169  if (context.mIMEState.mOpen == IMEState::OPEN_STATE_NOT_SUPPORTED) {
   2170    return NS_ERROR_NOT_IMPLEMENTED;
   2171  }
   2172  *aState = (context.mIMEState.mOpen == IMEState::OPEN);
   2173  return NS_OK;
   2174 }
   2175 
   2176 NS_IMETHODIMP
   2177 nsDOMWindowUtils::GetIMEStatus(uint32_t* aState) {
   2178  NS_ENSURE_ARG_POINTER(aState);
   2179 
   2180  nsCOMPtr<nsIWidget> widget = GetWidget();
   2181  if (!widget) return NS_ERROR_FAILURE;
   2182 
   2183  InputContext context = widget->GetInputContext();
   2184  *aState = static_cast<uint32_t>(context.mIMEState.mEnabled);
   2185  return NS_OK;
   2186 }
   2187 
   2188 NS_IMETHODIMP
   2189 nsDOMWindowUtils::GetInputContextURI(nsIURI** aURI) {
   2190  NS_ENSURE_ARG_POINTER(aURI);
   2191 
   2192  nsCOMPtr<nsIWidget> widget = GetWidget();
   2193  if (!widget) {
   2194    return NS_ERROR_FAILURE;
   2195  }
   2196 
   2197  nsCOMPtr<nsIURI> documentURI = widget->GetInputContext().mURI;
   2198  documentURI.forget(aURI);
   2199  return NS_OK;
   2200 }
   2201 
   2202 NS_IMETHODIMP
   2203 nsDOMWindowUtils::GetInputContextOrigin(uint32_t* aOrigin) {
   2204  NS_ENSURE_ARG_POINTER(aOrigin);
   2205 
   2206  nsCOMPtr<nsIWidget> widget = GetWidget();
   2207  if (!widget) {
   2208    return NS_ERROR_FAILURE;
   2209  }
   2210 
   2211  InputContext context = widget->GetInputContext();
   2212  static_assert(static_cast<uint32_t>(InputContext::Origin::ORIGIN_MAIN) ==
   2213                INPUT_CONTEXT_ORIGIN_MAIN);
   2214  static_assert(static_cast<uint32_t>(InputContext::Origin::ORIGIN_CONTENT) ==
   2215                INPUT_CONTEXT_ORIGIN_CONTENT);
   2216  MOZ_ASSERT(context.mOrigin == InputContext::Origin::ORIGIN_MAIN ||
   2217             context.mOrigin == InputContext::Origin::ORIGIN_CONTENT);
   2218  *aOrigin = static_cast<uint32_t>(context.mOrigin);
   2219  return NS_OK;
   2220 }
   2221 
   2222 NS_IMETHODIMP
   2223 nsDOMWindowUtils::GetNodeObservedByIMEContentObserver(nsINode** aNode) {
   2224  NS_ENSURE_ARG_POINTER(aNode);
   2225 
   2226  IMEContentObserver* observer = IMEStateManager::GetActiveContentObserver();
   2227  if (!observer) {
   2228    *aNode = nullptr;
   2229    return NS_OK;
   2230  }
   2231  *aNode = do_AddRef(observer->GetObservingElement()).take();
   2232  return NS_OK;
   2233 }
   2234 
   2235 NS_IMETHODIMP
   2236 nsDOMWindowUtils::GetCanvasBackgroundColor(nsAString& aColor) {
   2237  if (RefPtr<Document> doc = GetDocument()) {
   2238    doc->FlushPendingNotifications(FlushType::Frames);
   2239  }
   2240  nscolor color = NS_RGB(255, 255, 255);
   2241  if (PresShell* presShell = GetPresShell()) {
   2242    color = presShell->ComputeCanvasBackground().mViewport.mColor;
   2243  }
   2244  nsStyleUtil::GetSerializedColorValue(color, aColor);
   2245  return NS_OK;
   2246 }
   2247 
   2248 NS_IMETHODIMP
   2249 nsDOMWindowUtils::GetFocusedInputType(nsAString& aType) {
   2250  nsCOMPtr<nsIWidget> widget = GetWidget();
   2251  if (!widget) {
   2252    return NS_ERROR_FAILURE;
   2253  }
   2254 
   2255  aType = widget->GetInputContext().mHTMLInputType;
   2256  return NS_OK;
   2257 }
   2258 
   2259 NS_IMETHODIMP
   2260 nsDOMWindowUtils::GetFocusedActionHint(nsAString& aType) {
   2261  nsCOMPtr<nsIWidget> widget = GetWidget();
   2262  if (!widget) {
   2263    return NS_ERROR_FAILURE;
   2264  }
   2265 
   2266  aType = widget->GetInputContext().mActionHint;
   2267  return NS_OK;
   2268 }
   2269 
   2270 NS_IMETHODIMP
   2271 nsDOMWindowUtils::GetFocusedInputMode(nsAString& aInputMode) {
   2272  nsCOMPtr<nsIWidget> widget = GetWidget();
   2273  if (!widget) {
   2274    return NS_ERROR_FAILURE;
   2275  }
   2276  aInputMode = widget->GetInputContext().mHTMLInputMode;
   2277  return NS_OK;
   2278 }
   2279 
   2280 NS_IMETHODIMP
   2281 nsDOMWindowUtils::GetFocusedAutocapitalize(nsAString& aAutocapitalize) {
   2282  nsCOMPtr<nsIWidget> widget = GetWidget();
   2283  if (!widget) {
   2284    return NS_ERROR_FAILURE;
   2285  }
   2286  aAutocapitalize = widget->GetInputContext().mAutocapitalize;
   2287  return NS_OK;
   2288 }
   2289 
   2290 NS_IMETHODIMP
   2291 nsDOMWindowUtils::GetFocusedAutocorrect(bool* aAutocorrect) {
   2292  nsCOMPtr<nsIWidget> widget = GetWidget();
   2293  if (!widget) {
   2294    return NS_ERROR_FAILURE;
   2295  }
   2296  *aAutocorrect = widget->GetInputContext().mAutocorrect;
   2297  return NS_OK;
   2298 }
   2299 
   2300 NS_IMETHODIMP
   2301 nsDOMWindowUtils::GetViewId(Element* aElement, nsViewID* aResult) {
   2302  if (aElement && nsLayoutUtils::FindIDFor(aElement, aResult)) {
   2303    return NS_OK;
   2304  }
   2305  return NS_ERROR_NOT_AVAILABLE;
   2306 }
   2307 
   2308 NS_IMETHODIMP nsDOMWindowUtils::DispatchDOMEventViaPresShellForTesting(
   2309    nsINode* aTarget, Event* aEvent, bool* aRetVal) {
   2310  NS_ENSURE_STATE(aEvent);
   2311  aEvent->SetTrusted(true);
   2312  WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
   2313  NS_ENSURE_STATE(internalEvent);
   2314  // This API is currently used only by EventUtils.js.  Thus we should always
   2315  // set mIsSynthesizedForTests to true.
   2316  internalEvent->mFlags.mIsSynthesizedForTests = true;
   2317  nsCOMPtr<nsIContent> content = nsIContent::FromNodeOrNull(aTarget);
   2318  NS_ENSURE_STATE(content);
   2319  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2320  if (content->OwnerDoc()->GetWindow() != window) {
   2321    return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
   2322  }
   2323  nsCOMPtr<Document> targetDoc = content->GetUncomposedDoc();
   2324  NS_ENSURE_STATE(targetDoc);
   2325  RefPtr<PresShell> targetPresShell = targetDoc->GetPresShell();
   2326  NS_ENSURE_STATE(targetPresShell);
   2327 
   2328  WidgetGUIEvent* guiEvent = internalEvent->AsGUIEvent();
   2329  if (guiEvent && !guiEvent->mWidget) {
   2330    auto* pc = GetPresContext();
   2331    auto* widget = pc ? pc->GetRootWidget() : nullptr;
   2332    // In content, screen coordinates would have been
   2333    // transformed by BrowserParent::TransformParentToChild
   2334    // so we do that here.
   2335    if (widget) {
   2336      guiEvent->mWidget = widget;
   2337 
   2338      // Setting the widget makes the event's mRefPoint coordinates
   2339      // widget-relative, so we transform them from being
   2340      // screen-relative here.
   2341      guiEvent->mRefPoint -= widget->WidgetToScreenOffset();
   2342    }
   2343  }
   2344 
   2345  targetDoc->FlushPendingNotifications(FlushType::Layout);
   2346 
   2347  nsEventStatus status = nsEventStatus_eIgnore;
   2348  targetPresShell->HandleEventWithTarget(internalEvent, nullptr, content,
   2349                                         &status);
   2350  *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
   2351  return NS_OK;
   2352 }
   2353 
   2354 static void InitEvent(WidgetGUIEvent& aEvent,
   2355                      LayoutDeviceIntPoint* aPt = nullptr) {
   2356  if (aPt) {
   2357    aEvent.mRefPoint = *aPt;
   2358  }
   2359 }
   2360 
   2361 NS_IMETHODIMP
   2362 nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType, int64_t aOffset,
   2363                                        uint32_t aLength, int32_t aX,
   2364                                        int32_t aY, uint32_t aAdditionalFlags,
   2365                                        nsIQueryContentEventResult** aResult) {
   2366  *aResult = nullptr;
   2367 
   2368  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2369  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   2370 
   2371  nsIDocShell* docShell = window->GetDocShell();
   2372  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
   2373 
   2374  PresShell* presShell = docShell->GetPresShell();
   2375  NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
   2376 
   2377  nsPresContext* presContext = presShell->GetPresContext();
   2378  NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
   2379 
   2380  // get the widget to send the event to
   2381  nsCOMPtr<nsIWidget> widget = GetWidget();
   2382  if (!widget) {
   2383    return NS_ERROR_FAILURE;
   2384  }
   2385 
   2386  EventMessage message;
   2387  switch (aType) {
   2388    case QUERY_SELECTED_TEXT:
   2389      message = eQuerySelectedText;
   2390      break;
   2391    case QUERY_TEXT_CONTENT:
   2392      message = eQueryTextContent;
   2393      break;
   2394    case QUERY_CARET_RECT:
   2395      message = eQueryCaretRect;
   2396      break;
   2397    case QUERY_TEXT_RECT:
   2398      message = eQueryTextRect;
   2399      break;
   2400    case QUERY_EDITOR_RECT:
   2401      message = eQueryEditorRect;
   2402      break;
   2403    case QUERY_CHARACTER_AT_POINT:
   2404      message = eQueryCharacterAtPoint;
   2405      break;
   2406    case QUERY_TEXT_RECT_ARRAY:
   2407      message = eQueryTextRectArray;
   2408      break;
   2409    default:
   2410      return NS_ERROR_INVALID_ARG;
   2411  }
   2412 
   2413  SelectionType selectionType = SelectionType::eNormal;
   2414  static const uint32_t kSelectionFlags =
   2415      QUERY_CONTENT_FLAG_SELECTION_SPELLCHECK |
   2416      QUERY_CONTENT_FLAG_SELECTION_IME_RAWINPUT |
   2417      QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDRAWTEXT |
   2418      QUERY_CONTENT_FLAG_SELECTION_IME_CONVERTEDTEXT |
   2419      QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDCONVERTEDTEXT |
   2420      QUERY_CONTENT_FLAG_SELECTION_ACCESSIBILITY |
   2421      QUERY_CONTENT_FLAG_SELECTION_FIND |
   2422      QUERY_CONTENT_FLAG_SELECTION_URLSECONDARY |
   2423      QUERY_CONTENT_FLAG_SELECTION_URLSTRIKEOUT;
   2424  switch (aAdditionalFlags & kSelectionFlags) {
   2425    case QUERY_CONTENT_FLAG_SELECTION_SPELLCHECK:
   2426      selectionType = SelectionType::eSpellCheck;
   2427      break;
   2428    case QUERY_CONTENT_FLAG_SELECTION_IME_RAWINPUT:
   2429      selectionType = SelectionType::eIMERawClause;
   2430      break;
   2431    case QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDRAWTEXT:
   2432      selectionType = SelectionType::eIMESelectedRawClause;
   2433      break;
   2434    case QUERY_CONTENT_FLAG_SELECTION_IME_CONVERTEDTEXT:
   2435      selectionType = SelectionType::eIMEConvertedClause;
   2436      break;
   2437    case QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDCONVERTEDTEXT:
   2438      selectionType = SelectionType::eIMESelectedClause;
   2439      break;
   2440    case QUERY_CONTENT_FLAG_SELECTION_ACCESSIBILITY:
   2441      selectionType = SelectionType::eAccessibility;
   2442      break;
   2443    case QUERY_CONTENT_FLAG_SELECTION_FIND:
   2444      selectionType = SelectionType::eFind;
   2445      break;
   2446    case QUERY_CONTENT_FLAG_SELECTION_URLSECONDARY:
   2447      selectionType = SelectionType::eURLSecondary;
   2448      break;
   2449    case QUERY_CONTENT_FLAG_SELECTION_URLSTRIKEOUT:
   2450      selectionType = SelectionType::eURLStrikeout;
   2451      break;
   2452    case 0:
   2453      break;
   2454    default:
   2455      return NS_ERROR_INVALID_ARG;
   2456  }
   2457 
   2458  if (selectionType != SelectionType::eNormal &&
   2459      message != eQuerySelectedText) {
   2460    return NS_ERROR_INVALID_ARG;
   2461  }
   2462 
   2463  nsCOMPtr<nsIWidget> targetWidget = widget;
   2464  LayoutDeviceIntPoint pt(aX, aY);
   2465 
   2466  WidgetQueryContentEvent::Options options;
   2467  options.mUseNativeLineBreak =
   2468      !(aAdditionalFlags & QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
   2469  options.mRelativeToInsertionPoint =
   2470      (aAdditionalFlags &
   2471       QUERY_CONTENT_FLAG_OFFSET_RELATIVE_TO_INSERTION_POINT) != 0;
   2472  if (options.mRelativeToInsertionPoint) {
   2473    switch (message) {
   2474      case eQueryTextContent:
   2475      case eQueryCaretRect:
   2476      case eQueryTextRect:
   2477        break;
   2478      default:
   2479        return NS_ERROR_INVALID_ARG;
   2480    }
   2481  } else if (aOffset < 0) {
   2482    return NS_ERROR_INVALID_ARG;
   2483  }
   2484 
   2485  if (message == eQueryCharacterAtPoint) {
   2486    // Looking for the widget at the point.
   2487    nsIFrame* popupFrame = nsLayoutUtils::GetPopupFrameForPoint(
   2488        presContext->GetRootPresContext(), widget, pt);
   2489 
   2490    LayoutDeviceIntRect widgetBounds = widget->GetClientBounds();
   2491    widgetBounds.MoveTo(0, 0);
   2492 
   2493    // There is no popup frame at the point and the point isn't in our widget,
   2494    // we cannot process this request.
   2495    NS_ENSURE_TRUE(popupFrame || widgetBounds.Contains(pt), NS_ERROR_FAILURE);
   2496 
   2497    // Fire the event on the widget at the point
   2498    if (popupFrame) {
   2499      targetWidget = popupFrame->GetNearestWidget();
   2500    }
   2501  }
   2502 
   2503  pt += widget->WidgetToScreenOffset() - targetWidget->WidgetToScreenOffset();
   2504 
   2505  WidgetQueryContentEvent queryEvent(true, message, targetWidget);
   2506  InitEvent(queryEvent, &pt);
   2507 
   2508  switch (message) {
   2509    case eQueryTextContent:
   2510      queryEvent.InitForQueryTextContent(aOffset, aLength, options);
   2511      break;
   2512    case eQueryCaretRect:
   2513      queryEvent.InitForQueryCaretRect(aOffset, options);
   2514      break;
   2515    case eQueryTextRect:
   2516      queryEvent.InitForQueryTextRect(aOffset, aLength, options);
   2517      break;
   2518    case eQuerySelectedText:
   2519      queryEvent.InitForQuerySelectedText(selectionType, options);
   2520      break;
   2521    case eQueryTextRectArray:
   2522      queryEvent.InitForQueryTextRectArray(aOffset, aLength, options);
   2523      break;
   2524    default:
   2525      queryEvent.Init(options);
   2526      break;
   2527  }
   2528 
   2529  targetWidget->DispatchEvent(&queryEvent);
   2530 
   2531  auto* result = new nsQueryContentEventResult(std::move(queryEvent));
   2532  result->SetEventResult(widget);
   2533  NS_ADDREF(*aResult = result);
   2534  return NS_OK;
   2535 }
   2536 
   2537 NS_IMETHODIMP
   2538 nsDOMWindowUtils::SendSelectionSetEvent(uint32_t aOffset, uint32_t aLength,
   2539                                        uint32_t aAdditionalFlags,
   2540                                        bool* aResult) {
   2541  *aResult = false;
   2542 
   2543  // get the widget to send the event to
   2544  nsCOMPtr<nsIWidget> widget = GetWidget();
   2545  if (!widget) {
   2546    return NS_ERROR_FAILURE;
   2547  }
   2548 
   2549  WidgetSelectionEvent selectionEvent(true, eSetSelection, widget);
   2550  InitEvent(selectionEvent);
   2551 
   2552  selectionEvent.mOffset = aOffset;
   2553  selectionEvent.mLength = aLength;
   2554  selectionEvent.mReversed = (aAdditionalFlags & SELECTION_SET_FLAG_REVERSE);
   2555  selectionEvent.mUseNativeLineBreak =
   2556      !(aAdditionalFlags & SELECTION_SET_FLAG_USE_XP_LINE_BREAK);
   2557 
   2558  widget->DispatchEvent(&selectionEvent);
   2559 
   2560  *aResult = selectionEvent.mSucceeded;
   2561  return NS_OK;
   2562 }
   2563 
   2564 NS_IMETHODIMP
   2565 nsDOMWindowUtils::SendContentCommandEvent(const nsAString& aType,
   2566                                          nsITransferable* aTransferable,
   2567                                          const nsAString& aString,
   2568                                          uint32_t aOffset,
   2569                                          const nsAString& aReplaceSrcString,
   2570                                          uint32_t aAdditionalFlags) {
   2571  // get the widget to send the event to
   2572  nsCOMPtr<nsIWidget> widget = GetWidget();
   2573  if (!widget) return NS_ERROR_FAILURE;
   2574 
   2575  EventMessage msg;
   2576  if (aType.EqualsLiteral("cut")) {
   2577    msg = eContentCommandCut;
   2578  } else if (aType.EqualsLiteral("copy")) {
   2579    msg = eContentCommandCopy;
   2580  } else if (aType.EqualsLiteral("paste")) {
   2581    msg = eContentCommandPaste;
   2582  } else if (aType.EqualsLiteral("delete")) {
   2583    msg = eContentCommandDelete;
   2584  } else if (aType.EqualsLiteral("undo")) {
   2585    msg = eContentCommandUndo;
   2586  } else if (aType.EqualsLiteral("redo")) {
   2587    msg = eContentCommandRedo;
   2588  } else if (aType.EqualsLiteral("insertText")) {
   2589    msg = eContentCommandInsertText;
   2590  } else if (aType.EqualsLiteral("replaceText")) {
   2591    msg = eContentCommandReplaceText;
   2592  } else if (aType.EqualsLiteral("pasteTransferable")) {
   2593    msg = eContentCommandPasteTransferable;
   2594  } else {
   2595    return NS_ERROR_FAILURE;
   2596  }
   2597 
   2598  WidgetContentCommandEvent event(true, msg, widget);
   2599  if (msg == eContentCommandInsertText) {
   2600    event.mString.emplace(aString);
   2601  } else if (msg == eContentCommandReplaceText) {
   2602    event.mString.emplace(aString);
   2603    event.mSelection.mReplaceSrcString = aReplaceSrcString;
   2604    event.mSelection.mOffset = aOffset;
   2605    event.mSelection.mPreventSetSelection =
   2606        !!(aAdditionalFlags & CONTENT_COMMAND_FLAG_PREVENT_SET_SELECTION);
   2607  } else if (msg == eContentCommandPasteTransferable) {
   2608    event.mTransferable = aTransferable;
   2609  }
   2610 
   2611  widget->DispatchEvent(&event);
   2612  return NS_OK;
   2613 }
   2614 
   2615 NS_IMETHODIMP
   2616 nsDOMWindowUtils::GetClassName(JS::Handle<JS::Value> aObject, JSContext* aCx,
   2617                               char** aName) {
   2618  // Our argument must be a non-null object.
   2619  if (aObject.isPrimitive()) {
   2620    return NS_ERROR_XPC_BAD_CONVERT_JS;
   2621  }
   2622 
   2623  *aName = NS_xstrdup(JS::GetClass(aObject.toObjectOrNull())->name);
   2624  return NS_OK;
   2625 }
   2626 
   2627 NS_IMETHODIMP
   2628 nsDOMWindowUtils::GetVisitedDependentComputedStyle(
   2629    Element* aElement, const nsAString& aPseudoElement,
   2630    const nsAString& aPropertyName, nsAString& aResult) {
   2631  aResult.Truncate();
   2632 
   2633  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2634  NS_ENSURE_STATE(window && aElement);
   2635  nsCOMPtr<nsPIDOMWindowInner> innerWindow = window->GetCurrentInnerWindow();
   2636  NS_ENSURE_STATE(innerWindow);
   2637 
   2638  nsCOMPtr<nsICSSDeclaration> decl;
   2639  {
   2640    ErrorResult rv;
   2641    decl = innerWindow->GetComputedStyle(*aElement, aPseudoElement, rv);
   2642    RETURN_NSRESULT_ON_FAILURE(rv);
   2643  }
   2644 
   2645  nsAutoCString result;
   2646 
   2647  static_cast<nsComputedDOMStyle*>(decl.get())->SetExposeVisitedStyle(true);
   2648  decl->GetPropertyValue(NS_ConvertUTF16toUTF8(aPropertyName), result);
   2649  static_cast<nsComputedDOMStyle*>(decl.get())->SetExposeVisitedStyle(false);
   2650 
   2651  CopyUTF8toUTF16(result, aResult);
   2652  return NS_OK;
   2653 }
   2654 
   2655 NS_IMETHODIMP
   2656 nsDOMWindowUtils::EnterModalState() {
   2657  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2658  NS_ENSURE_STATE(window);
   2659 
   2660  window->EnterModalState();
   2661  return NS_OK;
   2662 }
   2663 
   2664 NS_IMETHODIMP
   2665 nsDOMWindowUtils::LeaveModalState() {
   2666  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2667  NS_ENSURE_STATE(window);
   2668 
   2669  window->LeaveModalState();
   2670  return NS_OK;
   2671 }
   2672 
   2673 NS_IMETHODIMP
   2674 nsDOMWindowUtils::IsInModalState(bool* retval) {
   2675  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2676  NS_ENSURE_STATE(window);
   2677 
   2678  *retval = nsGlobalWindowOuter::Cast(window)->IsInModalState();
   2679  return NS_OK;
   2680 }
   2681 
   2682 NS_IMETHODIMP
   2683 nsDOMWindowUtils::SuspendTimeouts() {
   2684  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2685  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   2686 
   2687  nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
   2688  NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE);
   2689 
   2690  inner->Suspend();
   2691 
   2692  return NS_OK;
   2693 }
   2694 
   2695 NS_IMETHODIMP
   2696 nsDOMWindowUtils::ResumeTimeouts() {
   2697  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   2698  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   2699 
   2700  nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
   2701  NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE);
   2702 
   2703  inner->Resume();
   2704 
   2705  return NS_OK;
   2706 }
   2707 
   2708 NS_IMETHODIMP
   2709 nsDOMWindowUtils::GetLayerManagerType(nsAString& aType) {
   2710  nsCOMPtr<nsIWidget> widget = GetWidget();
   2711  if (!widget) return NS_ERROR_FAILURE;
   2712 
   2713  WindowRenderer* renderer = widget->GetWindowRenderer();
   2714  if (!renderer) return NS_ERROR_FAILURE;
   2715 
   2716  renderer->GetBackendName(aType);
   2717 
   2718  return NS_OK;
   2719 }
   2720 
   2721 NS_IMETHODIMP
   2722 nsDOMWindowUtils::GetLayerManagerRemote(bool* retval) {
   2723  nsCOMPtr<nsIWidget> widget = GetWidget();
   2724  if (!widget) return NS_ERROR_FAILURE;
   2725 
   2726  WindowRenderer* renderer = widget->GetWindowRenderer();
   2727  if (!renderer) return NS_ERROR_FAILURE;
   2728 
   2729  *retval = !!renderer->AsKnowsCompositor();
   2730  return NS_OK;
   2731 }
   2732 
   2733 NS_IMETHODIMP
   2734 nsDOMWindowUtils::GetIsWebRenderRequested(bool* retval) {
   2735  *retval = gfxPlatform::WebRenderPrefEnabled() ||
   2736            gfxPlatform::WebRenderEnvvarEnabled();
   2737  return NS_OK;
   2738 }
   2739 
   2740 NS_IMETHODIMP
   2741 nsDOMWindowUtils::GetCurrentAudioBackend(nsAString& aBackend) {
   2742  CubebUtils::GetCurrentBackend(aBackend);
   2743  return NS_OK;
   2744 }
   2745 
   2746 NS_IMETHODIMP
   2747 nsDOMWindowUtils::GetCurrentMaxAudioChannels(uint32_t* aChannels) {
   2748  *aChannels = CubebUtils::MaxNumberOfChannels();
   2749  return NS_OK;
   2750 }
   2751 
   2752 NS_IMETHODIMP
   2753 nsDOMWindowUtils::GetCurrentPreferredSampleRate(uint32_t* aRate) {
   2754  nsCOMPtr<Document> doc = GetDocument();
   2755  *aRate = CubebUtils::PreferredSampleRate(
   2756      doc ? doc->ShouldResistFingerprinting(RFPTarget::AudioSampleRate)
   2757          : nsContentUtils::ShouldResistFingerprinting(
   2758                "Fallback", RFPTarget::AudioSampleRate));
   2759  return NS_OK;
   2760 }
   2761 
   2762 NS_IMETHODIMP
   2763 nsDOMWindowUtils::DefaultDevicesRoundTripLatency(Promise** aOutPromise) {
   2764  NS_ENSURE_ARG_POINTER(aOutPromise);
   2765  *aOutPromise = nullptr;
   2766 
   2767  nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow);
   2768  NS_ENSURE_STATE(outer);
   2769  nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
   2770  NS_ENSURE_STATE(inner);
   2771 
   2772  ErrorResult err;
   2773  RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err);
   2774  if (NS_WARN_IF(err.Failed())) {
   2775    return err.StealNSResult();
   2776  }
   2777 
   2778  NS_ADDREF(promise.get());
   2779  void* p = reinterpret_cast<void*>(promise.get());
   2780  NS_DispatchBackgroundTask(
   2781      NS_NewRunnableFunction("DefaultDevicesRoundTripLatency", [p]() {
   2782        double mean, stddev;
   2783        bool success =
   2784            CubebUtils::EstimatedLatencyDefaultDevices(&mean, &stddev);
   2785 
   2786        NS_DispatchToMainThread(NS_NewRunnableFunction(
   2787            "DefaultDevicesRoundTripLatency", [p, success, mean, stddev]() {
   2788              Promise* promise = reinterpret_cast<Promise*>(p);
   2789              if (!success) {
   2790                promise->MaybeReject(NS_ERROR_FAILURE);
   2791                NS_RELEASE(promise);
   2792                return;
   2793              }
   2794              nsTArray<double> a;
   2795              a.AppendElement(mean);
   2796              a.AppendElement(stddev);
   2797              promise->MaybeResolve(a);
   2798              NS_RELEASE(promise);
   2799            }));
   2800      }));
   2801 
   2802  promise.forget(aOutPromise);
   2803  return NS_OK;
   2804 }
   2805 
   2806 NS_IMETHODIMP
   2807 nsDOMWindowUtils::AudioDevices(uint16_t aSide, nsIArray** aDevices) {
   2808  NS_ENSURE_ARG_POINTER(aDevices);
   2809  NS_ENSURE_ARG((aSide == AUDIO_INPUT) || (aSide == AUDIO_OUTPUT));
   2810  *aDevices = nullptr;
   2811 
   2812  nsresult rv = NS_OK;
   2813  nsCOMPtr<nsIMutableArray> devices =
   2814      do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   2815  NS_ENSURE_SUCCESS(rv, rv);
   2816 
   2817  RefPtr<CubebDeviceEnumerator> enumerator = Enumerator::GetInstance();
   2818  RefPtr<const CubebDeviceEnumerator::AudioDeviceSet> collection;
   2819  if (aSide == AUDIO_INPUT) {
   2820    collection = enumerator->EnumerateAudioInputDevices();
   2821  } else {
   2822    collection = enumerator->EnumerateAudioOutputDevices();
   2823  }
   2824 
   2825  for (const auto& device : *collection) {
   2826    devices->AppendElement(device);
   2827  }
   2828 
   2829  devices.forget(aDevices);
   2830 
   2831  return NS_OK;
   2832 }
   2833 
   2834 NS_IMETHODIMP
   2835 nsDOMWindowUtils::StartFrameTimeRecording(uint32_t* startIndex) {
   2836  NS_ENSURE_ARG_POINTER(startIndex);
   2837 
   2838  nsCOMPtr<nsIWidget> widget = GetWidget();
   2839  if (!widget) return NS_ERROR_FAILURE;
   2840 
   2841  WindowRenderer* renderer = widget->GetWindowRenderer();
   2842  if (!renderer) return NS_ERROR_FAILURE;
   2843 
   2844  const uint32_t kRecordingMinSize = 60 * 10;       // 10 seconds @60 fps.
   2845  const uint32_t kRecordingMaxSize = 60 * 60 * 60;  // One hour
   2846  uint32_t bufferSize =
   2847      Preferences::GetUint("toolkit.framesRecording.bufferSize", uint32_t(0));
   2848  bufferSize = std::min(bufferSize, kRecordingMaxSize);
   2849  bufferSize = std::max(bufferSize, kRecordingMinSize);
   2850  *startIndex = renderer->StartFrameTimeRecording(bufferSize);
   2851 
   2852  return NS_OK;
   2853 }
   2854 
   2855 NS_IMETHODIMP
   2856 nsDOMWindowUtils::StopFrameTimeRecording(uint32_t startIndex,
   2857                                         nsTArray<float>& frameIntervals) {
   2858  nsCOMPtr<nsIWidget> widget = GetWidget();
   2859  if (!widget) return NS_ERROR_FAILURE;
   2860 
   2861  WindowRenderer* renderer = widget->GetWindowRenderer();
   2862  if (!renderer) return NS_ERROR_FAILURE;
   2863 
   2864  renderer->StopFrameTimeRecording(startIndex, frameIntervals);
   2865 
   2866  return NS_OK;
   2867 }
   2868 
   2869 NS_IMETHODIMP
   2870 nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds) {
   2871  // Before we advance the time, we should trigger any animations that are
   2872  // waiting to start. This is because there are many tests that call this
   2873  // which expect animations to start immediately. Ideally, we should make
   2874  // all these tests do an asynchronous wait on the corresponding animation's
   2875  // 'ready' promise before continuing. Then we could remove the special
   2876  // handling here and the code path followed when testing would more closely
   2877  // match the code path during regular operation. Filed as bug 1112957.
   2878  nsPresContext* presContext = GetPresContext();
   2879  if (presContext) {
   2880    presContext->Document()->Timeline()->TriggerAllPendingAnimationsNow();
   2881 
   2882    RefPtr<nsRefreshDriver> driver = presContext->RefreshDriver();
   2883    driver->AdvanceTimeAndRefresh(aMilliseconds);
   2884 
   2885    if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
   2886      wrbc->SendSetTestSampleTime(driver->MostRecentRefresh());
   2887    }
   2888  }
   2889 
   2890  return NS_OK;
   2891 }
   2892 
   2893 NS_IMETHODIMP
   2894 nsDOMWindowUtils::GetLastTransactionId(uint64_t* aLastTransactionId) {
   2895  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
   2896  if (!docShell) {
   2897    return NS_ERROR_UNEXPECTED;
   2898  }
   2899 
   2900  nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
   2901  docShell->GetInProcessRootTreeItem(getter_AddRefs(rootTreeItem));
   2902  docShell = do_QueryInterface(rootTreeItem);
   2903  if (!docShell) {
   2904    return NS_ERROR_UNEXPECTED;
   2905  }
   2906 
   2907  nsPresContext* presContext = docShell->GetPresContext();
   2908  if (!presContext) {
   2909    return NS_ERROR_UNEXPECTED;
   2910  }
   2911 
   2912  nsRefreshDriver* driver = presContext->RefreshDriver();
   2913  *aLastTransactionId = uint64_t(driver->LastTransactionId());
   2914  return NS_OK;
   2915 }
   2916 
   2917 NS_IMETHODIMP
   2918 nsDOMWindowUtils::RestoreNormalRefresh() {
   2919  // Kick the compositor out of test mode before the refresh driver, so that
   2920  // the refresh driver doesn't send an update that gets ignored by the
   2921  // compositor.
   2922  if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
   2923    wrbc->SendLeaveTestMode();
   2924  }
   2925 
   2926  if (nsPresContext* pc = GetPresContext()) {
   2927    nsRefreshDriver* driver = pc->RefreshDriver();
   2928    driver->RestoreNormalRefresh();
   2929  }
   2930 
   2931  return NS_OK;
   2932 }
   2933 
   2934 NS_IMETHODIMP
   2935 nsDOMWindowUtils::GetIsTestControllingRefreshes(bool* aResult) {
   2936  nsPresContext* pc = GetPresContext();
   2937  *aResult =
   2938      pc ? pc->RefreshDriver()->IsTestControllingRefreshesEnabled() : false;
   2939 
   2940  return NS_OK;
   2941 }
   2942 
   2943 NS_IMETHODIMP
   2944 nsDOMWindowUtils::GetAsyncPanZoomEnabled(bool* aResult) {
   2945  nsIWidget* widget = GetWidget();
   2946  if (widget) {
   2947    *aResult = widget->AsyncPanZoomEnabled();
   2948  } else {
   2949    *aResult = gfxPlatform::AsyncPanZoomEnabled();
   2950  }
   2951  return NS_OK;
   2952 }
   2953 
   2954 NS_IMETHODIMP
   2955 nsDOMWindowUtils::SetAsyncScrollOffset(Element* aElement, float aX, float aY) {
   2956  if (!aElement) {
   2957    return NS_ERROR_INVALID_ARG;
   2958  }
   2959  ScrollableLayerGuid::ViewID viewId;
   2960  if (!nsLayoutUtils::FindIDFor(aElement, &viewId)) {
   2961    return NS_ERROR_UNEXPECTED;
   2962  }
   2963  nsIWidget* widget = GetWidget();
   2964  if (!widget) {
   2965    return NS_ERROR_FAILURE;
   2966  }
   2967  WindowRenderer* renderer = widget->GetWindowRenderer();
   2968  if (!renderer) {
   2969    return NS_ERROR_FAILURE;
   2970  }
   2971  if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
   2972    WebRenderBridgeChild* wrbc = wr->WrBridge();
   2973    if (!wrbc) {
   2974      return NS_ERROR_UNEXPECTED;
   2975    }
   2976    wrbc->SendSetAsyncScrollOffset(viewId, aX, aY);
   2977    return NS_OK;
   2978  }
   2979  return NS_ERROR_UNEXPECTED;
   2980 }
   2981 
   2982 NS_IMETHODIMP
   2983 nsDOMWindowUtils::SetAsyncZoom(Element* aRootElement, float aValue) {
   2984  if (!aRootElement) {
   2985    return NS_ERROR_INVALID_ARG;
   2986  }
   2987  ScrollableLayerGuid::ViewID viewId;
   2988  if (!nsLayoutUtils::FindIDFor(aRootElement, &viewId)) {
   2989    return NS_ERROR_UNEXPECTED;
   2990  }
   2991  nsIWidget* widget = GetWidget();
   2992  if (!widget) {
   2993    return NS_ERROR_FAILURE;
   2994  }
   2995  WindowRenderer* renderer = widget->GetWindowRenderer();
   2996  if (!renderer) {
   2997    return NS_ERROR_FAILURE;
   2998  }
   2999  if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
   3000    WebRenderBridgeChild* wrbc = wr->WrBridge();
   3001    if (!wrbc) {
   3002      return NS_ERROR_UNEXPECTED;
   3003    }
   3004    wrbc->SendSetAsyncZoom(viewId, aValue);
   3005    return NS_OK;
   3006  }
   3007  return NS_ERROR_UNEXPECTED;
   3008 }
   3009 
   3010 NS_IMETHODIMP
   3011 nsDOMWindowUtils::FlushApzRepaints(Element* aElement, bool* aOutResult) {
   3012  nsIWidget* widget = GetWidgetForElement(aElement);
   3013  if (!widget) {
   3014    *aOutResult = false;
   3015    return NS_OK;
   3016  }
   3017  // If APZ is not enabled, this function is a no-op.
   3018  if (!widget->AsyncPanZoomEnabled()) {
   3019    *aOutResult = false;
   3020    return NS_OK;
   3021  }
   3022  WindowRenderer* renderer = widget->GetWindowRenderer();
   3023  if (!renderer) {
   3024    *aOutResult = false;
   3025    return NS_OK;
   3026  }
   3027  if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
   3028    WebRenderBridgeChild* wrbc = wr->WrBridge();
   3029    if (!wrbc) {
   3030      return NS_ERROR_UNEXPECTED;
   3031    }
   3032    wrbc->SendFlushApzRepaints();
   3033    *aOutResult = true;
   3034    return NS_OK;
   3035  }
   3036  *aOutResult = false;
   3037  return NS_OK;
   3038 }
   3039 
   3040 NS_IMETHODIMP
   3041 nsDOMWindowUtils::DisableApzForElement(Element* aElement) {
   3042  aElement->SetProperty(nsGkAtoms::apzDisabled, reinterpret_cast<void*>(true));
   3043  if (ScrollContainerFrame* sf =
   3044          nsLayoutUtils::FindScrollContainerFrameFor(aElement)) {
   3045    sf->SchedulePaint();
   3046  }
   3047  return NS_OK;
   3048 }
   3049 
   3050 NS_IMETHODIMP
   3051 nsDOMWindowUtils::IsApzDisabledForElement(Element* aElement, bool* aOutResult) {
   3052  *aOutResult = nsLayoutUtils::ShouldDisableApzForElement(aElement);
   3053  return NS_OK;
   3054 }
   3055 
   3056 static nsTArray<ScrollContainerFrame*> CollectScrollableAncestors(
   3057    nsIFrame* aStart) {
   3058  nsTArray<ScrollContainerFrame*> result;
   3059  nsIFrame* frame = aStart;
   3060  while (frame) {
   3061    frame = DisplayPortUtils::OneStepInAsyncScrollableAncestorChain(frame);
   3062    if (!frame) {
   3063      break;
   3064    }
   3065    ScrollContainerFrame* scrollAncestor =
   3066        nsLayoutUtils::GetAsyncScrollableAncestorFrame(frame);
   3067    if (!scrollAncestor) {
   3068      break;
   3069    }
   3070    result.AppendElement(scrollAncestor);
   3071    frame = do_QueryFrame(scrollAncestor);
   3072  }
   3073  return result;
   3074 }
   3075 
   3076 struct CaretInfo {
   3077  /* the text content including the caret */
   3078  nsIContent* textContent;
   3079  /* the text frame bounds relative to the root scroll contaner frame */
   3080  CSSRect textFrameBoundsRelativeToRootScroller;
   3081  /* the caret rect relative to the text frame */
   3082  Maybe<nsRect> caretRectRelativeToTextFrame;
   3083  /* the primary frame or the text frame for the caret */
   3084  nsIFrame* frame;
   3085 };
   3086 
   3087 static CaretInfo GetCaretContentAndBounds(
   3088    const ScrollContainerFrame* aRootScrollContainerFrame, Element* aElement) {
   3089  nsIContent* content = aElement;
   3090  CSSRect bounds;
   3091 
   3092  if (!aRootScrollContainerFrame) {
   3093    return CaretInfo{content, bounds, Nothing(), content->GetPrimaryFrame()};
   3094  }
   3095 
   3096  Maybe<nsRect> caretRect;
   3097  // When focused elment is content editable or <textarea> element,
   3098  // focused element will have multi-line content.
   3099  nsIFrame* frame = aElement->GetPrimaryFrame();
   3100  if (frame) {
   3101    RefPtr<nsCaret> caret = frame->PresShell()->GetCaret();
   3102    if (caret && caret->IsVisible()) {
   3103      nsRect rect;
   3104      if (nsIFrame* textFrame = caret->GetGeometry(&rect)) {
   3105        // This |textFrame| is a text frame and the returned rectangle
   3106        // represents the caret position relative to the text frame, so we need
   3107        // to pass the rectangle to ScrollFrameIntoView along with the text
   3108        // frame.
   3109        bounds = nsLayoutUtils::GetBoundingFrameRect(frame,
   3110                                                     aRootScrollContainerFrame);
   3111        content = frame->GetContent();
   3112        caretRect = Some(rect);
   3113        frame = textFrame;
   3114      }
   3115    }
   3116  }
   3117  if (bounds.IsEmpty()) {
   3118    // Fallback if no caret frame.
   3119    bounds = nsLayoutUtils::GetBoundingContentRect(aElement,
   3120                                                   aRootScrollContainerFrame);
   3121  }
   3122 
   3123  return CaretInfo{content, bounds, caretRect, frame};
   3124 }
   3125 
   3126 NS_IMETHODIMP
   3127 nsDOMWindowUtils::ZoomToFocusedInput() {
   3128  if (!Preferences::GetBool("apz.zoom-to-focused-input.enabled")) {
   3129    APZZTFI_LOG("disabled by pref");
   3130    return NS_OK;
   3131  }
   3132 
   3133  nsIWidget* widget = GetWidget();
   3134  if (!widget) {
   3135    return NS_OK;
   3136  }
   3137 
   3138  // If APZ is not enabled, this function is a no-op.
   3139  //
   3140  // FIXME(emilio): This is not quite true anymore now that we also
   3141  // ScrollIntoView() too...
   3142  if (!widget->AsyncPanZoomEnabled()) {
   3143    return NS_OK;
   3144  }
   3145 
   3146  const RefPtr<Element> element = nsFocusManager::GetFocusedElementStatic();
   3147  if (!element) {
   3148    APZZTFI_LOG("no focused element");
   3149    return NS_OK;
   3150  }
   3151 
   3152  RefPtr<PresShell> presShell =
   3153      APZCCallbackHelper::GetRootContentDocumentPresShellForContent(element);
   3154  if (!presShell) {
   3155    return NS_OK;
   3156  }
   3157 
   3158  ScrollContainerFrame* rootScrollContainerFrame =
   3159      presShell->GetRootScrollContainerFrame();
   3160  auto caretInfo = GetCaretContentAndBounds(rootScrollContainerFrame, element);
   3161  APZZTFI_LOG("calculated rect %s (caret rect %s)",
   3162              ToString(caretInfo.textFrameBoundsRelativeToRootScroller).c_str(),
   3163              ToString(caretInfo.caretRectRelativeToTextFrame).c_str());
   3164 
   3165  // The content may be inside a scrollable subframe inside a non-scrollable
   3166  // root content document. In this scenario, we want to ensure that the
   3167  // main-thread side knows to scroll the content into view before we get
   3168  // the bounding content rect and ask APZ to zoom in to the target content.
   3169  if (caretInfo.frame) {
   3170    presShell->ScrollFrameIntoView(
   3171        caretInfo.frame, caretInfo.caretRectRelativeToTextFrame,
   3172        ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotVisible),
   3173        ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotVisible),
   3174        ScrollFlags::ForZoomToFocusedInput);
   3175  }
   3176 
   3177  RefPtr<Document> document = presShell->GetDocument();
   3178  if (!document) {
   3179    return NS_OK;
   3180  }
   3181 
   3182  uint32_t presShellId;
   3183  ScrollableLayerGuid::ViewID viewId;
   3184  if (!APZCCallbackHelper::GetOrCreateScrollIdentifiers(
   3185          document->GetDocumentElement(), &presShellId, &viewId)) {
   3186    return NS_OK;
   3187  }
   3188 
   3189  TouchBehaviorFlags tbf =
   3190      layers::TouchActionHelper::GetAllowedTouchBehaviorForFrame(
   3191          element->GetPrimaryFrame());
   3192 
   3193  uint32_t flags = layers::DISABLE_ZOOM_OUT | layers::ZOOM_TO_FOCUSED_INPUT;
   3194  if (!Preferences::GetBool("formhelper.autozoom") ||
   3195      Preferences::GetBool("formhelper.autozoom.force-disable.test-only",
   3196                           /* aFallback = */ false) ||
   3197      !(tbf & AllowedTouchBehavior::ANIMATING_ZOOM)) {
   3198    flags |= layers::PAN_INTO_VIEW_ONLY;
   3199  } else {
   3200    flags |= layers::ONLY_ZOOM_TO_DEFAULT_SCALE;
   3201  }
   3202 
   3203  if (caretInfo.textFrameBoundsRelativeToRootScroller.IsEmpty()) {
   3204    // Do not zoom on empty bounds. Bail out.
   3205    return NS_OK;
   3206  }
   3207 
   3208  caretInfo.textFrameBoundsRelativeToRootScroller -=
   3209      CSSPoint::FromAppUnits(rootScrollContainerFrame->GetScrollPosition());
   3210 
   3211  bool waitForRefresh = false;
   3212  for (ScrollContainerFrame* scrollAncestor :
   3213       CollectScrollableAncestors(element->GetPrimaryFrame())) {
   3214    if (scrollAncestor->HasScrollUpdates()) {
   3215      waitForRefresh = true;
   3216      break;
   3217    }
   3218  }
   3219  APZZTFI_LOG("zooming to rect %s with flags %d, waitForRefresh=%d",
   3220              ToString(caretInfo.textFrameBoundsRelativeToRootScroller).c_str(),
   3221              flags, waitForRefresh);
   3222  if (waitForRefresh) {
   3223    waitForRefresh = false;
   3224    if (nsPresContext* presContext = presShell->GetPresContext()) {
   3225      waitForRefresh = true;
   3226      presContext->RegisterManagedPostRefreshObserver(
   3227          new ManagedPostRefreshObserver(
   3228              presContext,
   3229              [widget = RefPtr<nsIWidget>(widget), presShellId, viewId,
   3230               bounds = caretInfo.textFrameBoundsRelativeToRootScroller,
   3231               flags](bool aWasCanceled) {
   3232                if (!aWasCanceled) {
   3233                  widget->ZoomToRect(presShellId, viewId, bounds, flags);
   3234                }
   3235                return ManagedPostRefreshObserver::Unregister::Yes;
   3236              }));
   3237    }
   3238  }
   3239  if (!waitForRefresh) {
   3240    widget->ZoomToRect(presShellId, viewId,
   3241                       caretInfo.textFrameBoundsRelativeToRootScroller, flags);
   3242  }
   3243 
   3244  return NS_OK;
   3245 }
   3246 
   3247 NS_IMETHODIMP
   3248 nsDOMWindowUtils::ComputeAnimationDistance(Element* aElement,
   3249                                           const nsAString& aProperty,
   3250                                           const nsAString& aValue1,
   3251                                           const nsAString& aValue2,
   3252                                           double* aResult) {
   3253  NS_ENSURE_ARG_POINTER(aElement);
   3254 
   3255  NS_ConvertUTF16toUTF8 prop(aProperty);
   3256 
   3257  NonCustomCSSPropertyId propertyId = nsCSSProps::LookupProperty(prop);
   3258  if (propertyId == eCSSProperty_UNKNOWN ||
   3259      nsCSSProps::IsShorthand(propertyId)) {
   3260    return NS_ERROR_ILLEGAL_VALUE;
   3261  }
   3262 
   3263  auto property = CSSPropertyId::FromIdOrCustomProperty(propertyId, prop);
   3264 
   3265  AnimationValue v1 = AnimationValue::FromString(
   3266      property, NS_ConvertUTF16toUTF8(aValue1), aElement);
   3267  AnimationValue v2 = AnimationValue::FromString(
   3268      property, NS_ConvertUTF16toUTF8(aValue2), aElement);
   3269  if (v1.IsNull() || v2.IsNull()) {
   3270    return NS_ERROR_ILLEGAL_VALUE;
   3271  }
   3272 
   3273  *aResult = v1.ComputeDistance(v2);
   3274  return NS_OK;
   3275 }
   3276 
   3277 NS_IMETHODIMP
   3278 nsDOMWindowUtils::GetUnanimatedComputedStyle(Element* aElement,
   3279                                             const nsAString& aPseudoElement,
   3280                                             const nsAString& aProperty,
   3281                                             int32_t aFlushType,
   3282                                             nsAString& aResult) {
   3283  if (!aElement) {
   3284    return NS_ERROR_INVALID_ARG;
   3285  }
   3286 
   3287  NS_ConvertUTF16toUTF8 prop(aProperty);
   3288 
   3289  NonCustomCSSPropertyId propertyId = nsCSSProps::LookupProperty(prop);
   3290  if (propertyId == eCSSProperty_UNKNOWN ||
   3291      nsCSSProps::IsShorthand(propertyId)) {
   3292    return NS_ERROR_INVALID_ARG;
   3293  }
   3294 
   3295  auto property = CSSPropertyId::FromIdOrCustomProperty(propertyId, prop);
   3296 
   3297  switch (aFlushType) {
   3298    case FLUSH_NONE:
   3299      break;
   3300    case FLUSH_STYLE: {
   3301      if (Document* doc = aElement->GetComposedDoc()) {
   3302        doc->FlushPendingNotifications(FlushType::Style);
   3303      }
   3304      break;
   3305    }
   3306    default:
   3307      return NS_ERROR_INVALID_ARG;
   3308  }
   3309 
   3310  RefPtr<PresShell> presShell = GetPresShell();
   3311  if (!presShell) {
   3312    return NS_ERROR_FAILURE;
   3313  }
   3314 
   3315  Maybe<PseudoStyleRequest> pseudo =
   3316      nsCSSPseudoElements::ParsePseudoElement(aPseudoElement);
   3317  if (!pseudo) {
   3318    return NS_ERROR_FAILURE;
   3319  }
   3320  RefPtr<const ComputedStyle> computedStyle =
   3321      nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(aElement, *pseudo);
   3322  if (!computedStyle) {
   3323    return NS_ERROR_FAILURE;
   3324  }
   3325 
   3326  RefPtr<StyleAnimationValue> value =
   3327      Servo_ComputedValues_ExtractAnimationValue(computedStyle, &property)
   3328          .Consume();
   3329  if (!value) {
   3330    return NS_ERROR_FAILURE;
   3331  }
   3332  if (!aElement->GetComposedDoc()) {
   3333    return NS_ERROR_FAILURE;
   3334  }
   3335  nsAutoCString result;
   3336  Servo_AnimationValue_Serialize(value, &property,
   3337                                 presShell->StyleSet()->RawData(), &result);
   3338  CopyUTF8toUTF16(result, aResult);
   3339  return NS_OK;
   3340 }
   3341 
   3342 NS_IMETHODIMP
   3343 nsDOMWindowUtils::GetDisplayDPI(float* aDPI) {
   3344  nsCOMPtr<nsIWidget> widget = GetWidget();
   3345  if (!widget) return NS_ERROR_FAILURE;
   3346 
   3347  *aDPI = widget->GetDPI();
   3348 
   3349  return NS_OK;
   3350 }
   3351 
   3352 NS_IMETHODIMP
   3353 nsDOMWindowUtils::CheckAndClearPaintedState(Element* aElement, bool* aResult) {
   3354  if (!aElement) {
   3355    return NS_ERROR_INVALID_ARG;
   3356  }
   3357 
   3358  nsIFrame* frame = aElement->GetPrimaryFrame();
   3359 
   3360  if (!frame) {
   3361    *aResult = false;
   3362    return NS_OK;
   3363  }
   3364 
   3365  // Get the outermost frame for the content node, so that we can test
   3366  // canvasframe invalidations by observing the documentElement.
   3367  for (;;) {
   3368    nsIFrame* parentFrame = frame->GetParent();
   3369    if (parentFrame && parentFrame->GetContent() == aElement) {
   3370      frame = parentFrame;
   3371    } else {
   3372      break;
   3373    }
   3374  }
   3375 
   3376  while (frame) {
   3377    if (!frame->CheckAndClearPaintedState()) {
   3378      *aResult = false;
   3379      return NS_OK;
   3380    }
   3381    frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame);
   3382  }
   3383  *aResult = true;
   3384  return NS_OK;
   3385 }
   3386 
   3387 NS_IMETHODIMP
   3388 nsDOMWindowUtils::CheckAndClearDisplayListState(Element* aElement,
   3389                                                bool* aResult) {
   3390  if (!aElement) {
   3391    return NS_ERROR_INVALID_ARG;
   3392  }
   3393 
   3394  nsIFrame* frame = aElement->GetPrimaryFrame();
   3395 
   3396  if (!frame) {
   3397    *aResult = false;
   3398    return NS_OK;
   3399  }
   3400 
   3401  // Get the outermost frame for the content node, so that we can test
   3402  // canvasframe invalidations by observing the documentElement.
   3403  for (;;) {
   3404    nsIFrame* parentFrame = frame->GetParent();
   3405    if (parentFrame && parentFrame->GetContent() == aElement) {
   3406      frame = parentFrame;
   3407    } else {
   3408      break;
   3409    }
   3410  }
   3411 
   3412  while (frame) {
   3413    if (!frame->CheckAndClearDisplayListState()) {
   3414      *aResult = false;
   3415      return NS_OK;
   3416    }
   3417    frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame);
   3418  }
   3419  *aResult = true;
   3420  return NS_OK;
   3421 }
   3422 
   3423 NS_IMETHODIMP
   3424 nsDOMWindowUtils::EnableDialogs() {
   3425  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   3426  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   3427 
   3428  nsGlobalWindowOuter::Cast(window)->EnableDialogs();
   3429  return NS_OK;
   3430 }
   3431 
   3432 NS_IMETHODIMP
   3433 nsDOMWindowUtils::DisableDialogs() {
   3434  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   3435  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   3436 
   3437  nsGlobalWindowOuter::Cast(window)->DisableDialogs();
   3438  return NS_OK;
   3439 }
   3440 
   3441 NS_IMETHODIMP
   3442 nsDOMWindowUtils::AreDialogsEnabled(bool* aResult) {
   3443  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   3444  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   3445 
   3446  *aResult = nsGlobalWindowOuter::Cast(window)->AreDialogsEnabled();
   3447  return NS_OK;
   3448 }
   3449 
   3450 NS_IMETHODIMP
   3451 nsDOMWindowUtils::ResetDialogAbuseState() {
   3452  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   3453  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   3454 
   3455  nsGlobalWindowOuter::Cast(window)
   3456      ->GetBrowsingContextGroup()
   3457      ->ResetDialogAbuseState();
   3458  return NS_OK;
   3459 }
   3460 
   3461 NS_IMETHODIMP
   3462 nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx,
   3463                            int64_t* _retval) {
   3464  if (aFile.isPrimitive()) {
   3465    *_retval = -1;
   3466    return NS_OK;
   3467  }
   3468 
   3469  JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull());
   3470 
   3471  Blob* blob = nullptr;
   3472  if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
   3473    *_retval = blob->GetFileId();
   3474    return NS_OK;
   3475  }
   3476 
   3477  *_retval = -1;
   3478  return NS_OK;
   3479 }
   3480 
   3481 NS_IMETHODIMP
   3482 nsDOMWindowUtils::GetFilePath(JS::Handle<JS::Value> aFile, JSContext* aCx,
   3483                              nsAString& _retval) {
   3484  if (aFile.isPrimitive()) {
   3485    _retval.Truncate();
   3486    return NS_OK;
   3487  }
   3488 
   3489  JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull());
   3490 
   3491  File* file = nullptr;
   3492  if (NS_SUCCEEDED(UNWRAP_OBJECT(File, &obj, file))) {
   3493    nsString filePath;
   3494    ErrorResult rv;
   3495    file->GetMozFullPathInternal(filePath, rv);
   3496    if (NS_WARN_IF(rv.Failed())) {
   3497      return rv.StealNSResult();
   3498    }
   3499 
   3500    _retval = filePath;
   3501    return NS_OK;
   3502  }
   3503 
   3504  _retval.Truncate();
   3505  return NS_OK;
   3506 }
   3507 
   3508 NS_IMETHODIMP
   3509 nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId,
   3510                                    int32_t* aRefCnt, int32_t* aDBRefCnt,
   3511                                    bool* aResult) {
   3512  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   3513  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   3514 
   3515  quota::PrincipalMetadata principalMetadata =
   3516      MOZ_TRY(quota::GetInfoFromWindow(window));
   3517 
   3518  RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
   3519  if (mgr) {
   3520    nsresult rv = mgr->BlockAndGetFileReferences(
   3521        principalMetadata.mIsPrivate ? quota::PERSISTENCE_TYPE_PRIVATE
   3522                                     : quota::PERSISTENCE_TYPE_DEFAULT,
   3523        principalMetadata.mOrigin, aDatabaseName, aId, aRefCnt, aDBRefCnt,
   3524        aResult);
   3525 
   3526    NS_ENSURE_SUCCESS(rv, rv);
   3527  } else {
   3528    *aRefCnt = *aDBRefCnt = -1;
   3529    *aResult = false;
   3530  }
   3531 
   3532  return NS_OK;
   3533 }
   3534 
   3535 NS_IMETHODIMP
   3536 nsDOMWindowUtils::FlushPendingFileDeletions() {
   3537  RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
   3538  if (mgr) {
   3539    nsresult rv = mgr->FlushPendingFileDeletions();
   3540    if (NS_WARN_IF(NS_FAILED(rv))) {
   3541      return rv;
   3542    }
   3543  }
   3544 
   3545  return NS_OK;
   3546 }
   3547 
   3548 NS_IMETHODIMP
   3549 nsDOMWindowUtils::StartPCCountProfiling(JSContext* cx) {
   3550  JS::StartPCCountProfiling(cx);
   3551  return NS_OK;
   3552 }
   3553 
   3554 NS_IMETHODIMP
   3555 nsDOMWindowUtils::StopPCCountProfiling(JSContext* cx) {
   3556  JS::StopPCCountProfiling(cx);
   3557  return NS_OK;
   3558 }
   3559 
   3560 NS_IMETHODIMP
   3561 nsDOMWindowUtils::PurgePCCounts(JSContext* cx) {
   3562  JS::PurgePCCounts(cx);
   3563  return NS_OK;
   3564 }
   3565 
   3566 NS_IMETHODIMP
   3567 nsDOMWindowUtils::GetPCCountScriptCount(JSContext* cx, int32_t* result) {
   3568  *result = JS::GetPCCountScriptCount(cx);
   3569  return NS_OK;
   3570 }
   3571 
   3572 NS_IMETHODIMP
   3573 nsDOMWindowUtils::GetPCCountScriptSummary(int32_t script, JSContext* cx,
   3574                                          nsAString& result) {
   3575  JSString* text = JS::GetPCCountScriptSummary(cx, script);
   3576  if (!text) return NS_ERROR_FAILURE;
   3577 
   3578  if (!AssignJSString(cx, result, text)) return NS_ERROR_FAILURE;
   3579 
   3580  return NS_OK;
   3581 }
   3582 
   3583 NS_IMETHODIMP
   3584 nsDOMWindowUtils::GetPCCountScriptContents(int32_t script, JSContext* cx,
   3585                                           nsAString& result) {
   3586  JSString* text = JS::GetPCCountScriptContents(cx, script);
   3587  if (!text) return NS_ERROR_FAILURE;
   3588 
   3589  if (!AssignJSString(cx, result, text)) return NS_ERROR_FAILURE;
   3590 
   3591  return NS_OK;
   3592 }
   3593 
   3594 NS_IMETHODIMP
   3595 nsDOMWindowUtils::GetPaintingSuppressed(bool* aPaintingSuppressed) {
   3596  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   3597  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   3598  nsIDocShell* docShell = window->GetDocShell();
   3599  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
   3600 
   3601  PresShell* presShell = docShell->GetPresShell();
   3602  NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
   3603 
   3604  *aPaintingSuppressed = presShell->IsPaintingSuppressed();
   3605  return NS_OK;
   3606 }
   3607 
   3608 NS_IMETHODIMP
   3609 nsDOMWindowUtils::SetVisualViewportSize(float aWidth, float aHeight) {
   3610  if (!(aWidth >= 0.0 && aHeight >= 0.0)) {
   3611    return NS_ERROR_ILLEGAL_VALUE;
   3612  }
   3613 
   3614  PresShell* presShell = GetPresShell();
   3615  if (!presShell) {
   3616    return NS_ERROR_FAILURE;
   3617  }
   3618 
   3619  presShell->SetVisualViewportSize(nsPresContext::CSSPixelsToAppUnits(aWidth),
   3620                                   nsPresContext::CSSPixelsToAppUnits(aHeight));
   3621 
   3622  return NS_OK;
   3623 }
   3624 
   3625 nsresult nsDOMWindowUtils::RemoteFrameFullscreenChanged(
   3626    Element* aFrameElement) {
   3627  nsCOMPtr<Document> doc = GetDocument();
   3628  NS_ENSURE_STATE(doc);
   3629 
   3630  doc->RemoteFrameFullscreenChanged(aFrameElement);
   3631  return NS_OK;
   3632 }
   3633 
   3634 nsresult nsDOMWindowUtils::RemoteFrameFullscreenReverted() {
   3635  nsCOMPtr<Document> doc = GetDocument();
   3636  NS_ENSURE_STATE(doc);
   3637 
   3638  doc->RemoteFrameFullscreenReverted();
   3639  return NS_OK;
   3640 }
   3641 
   3642 static void PrepareForFullscreenChange(nsIDocShell* aDocShell,
   3643                                       const nsSize& aSize,
   3644                                       nsSize* aOldSize = nullptr) {
   3645  if (!aDocShell) {
   3646    return;
   3647  }
   3648  PresShell* presShell = aDocShell->GetPresShell();
   3649  if (!presShell) {
   3650    return;
   3651  }
   3652  if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
   3653    rd->SetIsResizeSuppressed();
   3654    // Since we are suppressing the resize reflow which would originally
   3655    // be triggered by view manager, we need to ensure that the refresh
   3656    // driver actually schedules a flush, otherwise it may get stuck.
   3657    rd->SchedulePaint();
   3658  }
   3659  if (!aSize.IsEmpty()) {
   3660    nsCOMPtr<nsIDocumentViewer> viewer;
   3661    aDocShell->GetDocViewer(getter_AddRefs(viewer));
   3662    if (viewer) {
   3663      LayoutDeviceIntRect viewerBounds;
   3664      viewer->GetBounds(viewerBounds);
   3665      nscoord auPerDev = presShell->GetPresContext()->AppUnitsPerDevPixel();
   3666      if (aOldSize) {
   3667        *aOldSize =
   3668            LayoutDeviceIntSize::ToAppUnits(viewerBounds.Size(), auPerDev);
   3669      }
   3670      auto newSize = LayoutDeviceIntSize::FromAppUnitsRounded(aSize, auPerDev);
   3671      viewerBounds.SizeTo(newSize.width, newSize.height);
   3672      viewer->SetBounds(viewerBounds);
   3673    }
   3674  }
   3675 }
   3676 
   3677 NS_IMETHODIMP
   3678 nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal) {
   3679  PROFILER_MARKER_UNTYPED("Enter fullscreen", DOM);
   3680  nsCOMPtr<Document> doc = GetDocument();
   3681  NS_ENSURE_STATE(doc);
   3682 
   3683  // Notify the pres shell that we are starting fullscreen change, and
   3684  // set the window dimensions in advance. Since the resize message
   3685  // comes after the fullscreen change call, doing so could avoid an
   3686  // extra resize reflow after this point.
   3687  nsRect screenRect;
   3688  if (nsPresContext* presContext = GetPresContext()) {
   3689    screenRect = presContext->DeviceContext()->GetRect();
   3690  }
   3691  nsSize oldSize;
   3692  PrepareForFullscreenChange(GetDocShell(), screenRect.Size(), &oldSize);
   3693  OldWindowSize::Set(mWindow, oldSize);
   3694 
   3695  *aRetVal = Document::HandlePendingFullscreenRequests(doc);
   3696  return NS_OK;
   3697 }
   3698 
   3699 nsresult nsDOMWindowUtils::ExitFullscreen(bool aDontRestoreViewSize) {
   3700  PROFILER_MARKER_UNTYPED("Exit fullscreen", DOM);
   3701  nsCOMPtr<Document> doc = GetDocument();
   3702  NS_ENSURE_STATE(doc);
   3703 
   3704  // Although we would not use the old size if we have already exited
   3705  // fullscreen, we still want to cleanup in case we haven't.
   3706  nsSize oldSize = OldWindowSize::GetAndRemove(mWindow);
   3707  if (!doc->GetFullscreenElement()) {
   3708    return NS_OK;
   3709  }
   3710 
   3711  // Notify the pres shell that we are starting fullscreen change, and
   3712  // set the window dimensions in advance. Since the resize message
   3713  // comes after the fullscreen change call, doing so could avoid an
   3714  // extra resize reflow after this point.
   3715  PrepareForFullscreenChange(GetDocShell(),
   3716                             aDontRestoreViewSize ? nsSize() : oldSize);
   3717  Document::ExitFullscreenInDocTree(doc);
   3718  return NS_OK;
   3719 }
   3720 
   3721 NS_IMETHODIMP
   3722 nsDOMWindowUtils::SelectAtPoint(float aX, float aY, uint32_t aSelectBehavior,
   3723                                bool* _retval) {
   3724  *_retval = false;
   3725 
   3726  nsSelectionAmount amount;
   3727  switch (aSelectBehavior) {
   3728    case nsIDOMWindowUtils::SELECT_CHARACTER:
   3729      amount = eSelectCharacter;
   3730      break;
   3731    case nsIDOMWindowUtils::SELECT_CLUSTER:
   3732      amount = eSelectCluster;
   3733      break;
   3734    case nsIDOMWindowUtils::SELECT_WORD:
   3735      amount = eSelectWord;
   3736      break;
   3737    case nsIDOMWindowUtils::SELECT_LINE:
   3738      amount = eSelectLine;
   3739      break;
   3740    case nsIDOMWindowUtils::SELECT_BEGINLINE:
   3741      amount = eSelectBeginLine;
   3742      break;
   3743    case nsIDOMWindowUtils::SELECT_ENDLINE:
   3744      amount = eSelectEndLine;
   3745      break;
   3746    case nsIDOMWindowUtils::SELECT_PARAGRAPH:
   3747      amount = eSelectParagraph;
   3748      break;
   3749    case nsIDOMWindowUtils::SELECT_WORDNOSPACE:
   3750      amount = eSelectWordNoSpace;
   3751      break;
   3752    default:
   3753      return NS_ERROR_INVALID_ARG;
   3754  }
   3755 
   3756  PresShell* presShell = GetPresShell();
   3757  if (!presShell) {
   3758    return NS_ERROR_UNEXPECTED;
   3759  }
   3760 
   3761  // The root frame for this content window
   3762  nsIFrame* rootFrame = presShell->GetRootFrame();
   3763  if (!rootFrame) {
   3764    return NS_ERROR_UNEXPECTED;
   3765  }
   3766 
   3767  // Get the target frame at the client coordinates passed to us
   3768  nsPoint offset;
   3769  nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
   3770  LayoutDeviceIntPoint pt =
   3771      nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext());
   3772  nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(
   3773      widget, pt, RelativeTo{rootFrame});
   3774  nsIFrame* targetFrame =
   3775      nsLayoutUtils::GetFrameForPoint(RelativeTo{rootFrame}, ptInRoot);
   3776  // This can happen if the page hasn't loaded yet or if the point
   3777  // is outside the frame.
   3778  if (!targetFrame) {
   3779    return NS_ERROR_INVALID_ARG;
   3780  }
   3781 
   3782  // Convert point to coordinates relative to the target frame, which is
   3783  // what targetFrame's SelectByTypeAtPoint expects.
   3784  nsPoint relPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(
   3785      widget, pt, RelativeTo{targetFrame});
   3786 
   3787  nsresult rv = targetFrame->SelectByTypeAtPoint(relPoint, amount, amount,
   3788                                                 nsIFrame::SELECT_ACCUMULATE);
   3789  *_retval = !NS_FAILED(rv);
   3790  return NS_OK;
   3791 }
   3792 
   3793 static Document::additionalSheetType convertSheetType(uint32_t aSheetType) {
   3794  switch (aSheetType) {
   3795    case nsDOMWindowUtils::AGENT_SHEET:
   3796      return Document::eAgentSheet;
   3797    case nsDOMWindowUtils::USER_SHEET:
   3798      return Document::eUserSheet;
   3799    case nsDOMWindowUtils::AUTHOR_SHEET:
   3800      return Document::eAuthorSheet;
   3801    default:
   3802      NS_ASSERTION(false, "wrong type");
   3803      // we must return something although this should never happen
   3804      return Document::AdditionalSheetTypeCount;
   3805  }
   3806 }
   3807 
   3808 NS_IMETHODIMP
   3809 nsDOMWindowUtils::LoadSheet(nsIURI* aSheetURI, uint32_t aSheetType) {
   3810  NS_ENSURE_ARG_POINTER(aSheetURI);
   3811  NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
   3812                aSheetType == AUTHOR_SHEET);
   3813 
   3814  nsCOMPtr<Document> doc = GetDocument();
   3815  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
   3816 
   3817  Document::additionalSheetType type = convertSheetType(aSheetType);
   3818 
   3819  return doc->LoadAdditionalStyleSheet(type, aSheetURI);
   3820 }
   3821 
   3822 NS_IMETHODIMP
   3823 nsDOMWindowUtils::LoadSheetUsingURIString(const nsACString& aSheetURI,
   3824                                          uint32_t aSheetType) {
   3825  nsCOMPtr<nsIURI> uri;
   3826  nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI);
   3827  NS_ENSURE_SUCCESS(rv, rv);
   3828 
   3829  return LoadSheet(uri, aSheetType);
   3830 }
   3831 
   3832 NS_IMETHODIMP
   3833 nsDOMWindowUtils::AddSheet(nsIPreloadedStyleSheet* aSheet,
   3834                           uint32_t aSheetType) {
   3835  NS_ENSURE_ARG_POINTER(aSheet);
   3836  NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
   3837                aSheetType == AUTHOR_SHEET);
   3838 
   3839  nsCOMPtr<Document> doc = GetDocument();
   3840  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
   3841 
   3842  StyleSheet* sheet =
   3843      MOZ_TRY(static_cast<PreloadedStyleSheet*>(aSheet)->GetSheet());
   3844 
   3845  Document::additionalSheetType type = convertSheetType(aSheetType);
   3846  return doc->AddAdditionalStyleSheet(type, sheet);
   3847 }
   3848 
   3849 NS_IMETHODIMP
   3850 nsDOMWindowUtils::RemoveSheet(nsIURI* aSheetURI, uint32_t aSheetType) {
   3851  NS_ENSURE_ARG_POINTER(aSheetURI);
   3852  NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
   3853                aSheetType == AUTHOR_SHEET);
   3854 
   3855  nsCOMPtr<Document> doc = GetDocument();
   3856  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
   3857 
   3858  Document::additionalSheetType type = convertSheetType(aSheetType);
   3859 
   3860  doc->RemoveAdditionalStyleSheet(type, aSheetURI);
   3861  return NS_OK;
   3862 }
   3863 
   3864 NS_IMETHODIMP
   3865 nsDOMWindowUtils::RemoveSheetUsingURIString(const nsACString& aSheetURI,
   3866                                            uint32_t aSheetType) {
   3867  nsCOMPtr<nsIURI> uri;
   3868  nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI);
   3869  NS_ENSURE_SUCCESS(rv, rv);
   3870 
   3871  return RemoveSheet(uri, aSheetType);
   3872 }
   3873 
   3874 NS_IMETHODIMP
   3875 nsDOMWindowUtils::GetIsHandlingUserInput(bool* aHandlingUserInput) {
   3876  *aHandlingUserInput = UserActivation::IsHandlingUserInput();
   3877 
   3878  return NS_OK;
   3879 }
   3880 
   3881 NS_IMETHODIMP
   3882 nsDOMWindowUtils::GetMillisSinceLastUserInput(
   3883    double* aMillisSinceLastUserInput) {
   3884  TimeStamp lastInput = UserActivation::LatestUserInputStart();
   3885  if (lastInput.IsNull()) {
   3886    *aMillisSinceLastUserInput = -1.0f;
   3887    return NS_OK;
   3888  }
   3889 
   3890  *aMillisSinceLastUserInput = (TimeStamp::Now() - lastInput).ToMilliseconds();
   3891  return NS_OK;
   3892 }
   3893 
   3894 NS_IMETHODIMP
   3895 nsDOMWindowUtils::AllowScriptsToClose() {
   3896  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   3897  NS_ENSURE_STATE(window);
   3898  nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose();
   3899  return NS_OK;
   3900 }
   3901 
   3902 NS_IMETHODIMP
   3903 nsDOMWindowUtils::GetIsParentWindowMainWidgetVisible(bool* aIsVisible) {
   3904  if (!XRE_IsParentProcess()) {
   3905    MOZ_CRASH(
   3906        "IsParentWindowMainWidgetVisible is only available in the parent "
   3907        "process");
   3908  }
   3909 
   3910  // this should reflect the "is parent window visible" logic in
   3911  // nsWindowWatcher::OpenWindowInternal()
   3912  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   3913  NS_ENSURE_STATE(window);
   3914 
   3915  nsCOMPtr<nsIWidget> parentWidget;
   3916  nsIDocShell* docShell = window->GetDocShell();
   3917  if (docShell) {
   3918    nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
   3919    docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
   3920    nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(parentTreeOwner));
   3921    if (parentWindow) {
   3922      parentWidget = parentWindow->GetMainWidget();
   3923    }
   3924  }
   3925  if (!parentWidget) {
   3926    return NS_ERROR_NOT_AVAILABLE;
   3927  }
   3928 
   3929  *aIsVisible = parentWidget->IsVisible();
   3930  return NS_OK;
   3931 }
   3932 
   3933 NS_IMETHODIMP
   3934 nsDOMWindowUtils::IsNodeDisabledForEvents(nsINode* aNode, bool* aRetVal) {
   3935  *aRetVal = false;
   3936  nsINode* node = aNode;
   3937  while (node) {
   3938    if (node->IsHTMLFormControlElement()) {
   3939      nsGenericHTMLElement* element = nsGenericHTMLElement::FromNode(node);
   3940      WidgetEvent event(true, eVoidEvent);
   3941      if (element && element->IsDisabledForEvents(&event)) {
   3942        *aRetVal = true;
   3943        break;
   3944      }
   3945    }
   3946    node = node->GetParentNode();
   3947  }
   3948 
   3949  return NS_OK;
   3950 }
   3951 
   3952 NS_IMETHODIMP
   3953 nsDOMWindowUtils::DispatchEventToChromeOnly(EventTarget* aTarget, Event* aEvent,
   3954                                            bool* aRetVal) {
   3955  *aRetVal = false;
   3956  NS_ENSURE_STATE(aTarget && aEvent);
   3957  aEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
   3958  *aRetVal =
   3959      aTarget->DispatchEvent(*aEvent, CallerType::System, IgnoreErrors());
   3960  return NS_OK;
   3961 }
   3962 
   3963 static Result<nsIFrame*, nsresult> GetTargetFrame(
   3964    const Element* aElement, const nsAString& aPseudoElement) {
   3965  nsIFrame* frame = aElement->GetPrimaryFrame();
   3966  if (!aPseudoElement.IsEmpty()) {
   3967    if (aPseudoElement.EqualsLiteral("::before")) {
   3968      frame = nsLayoutUtils::GetBeforeFrame(aElement);
   3969    } else if (aPseudoElement.EqualsLiteral("::after")) {
   3970      frame = nsLayoutUtils::GetAfterFrame(aElement);
   3971    } else {
   3972      return Err(NS_ERROR_INVALID_ARG);
   3973    }
   3974  }
   3975  return frame;
   3976 }
   3977 
   3978 static OMTAValue GetOMTAValue(nsIFrame* aFrame, DisplayItemType aDisplayItemKey,
   3979                              WebRenderBridgeChild* aWebRenderBridgeChild) {
   3980  OMTAValue value = mozilla::null_t();
   3981 
   3982  if (aWebRenderBridgeChild) {
   3983    RefPtr<WebRenderAnimationData> animationData =
   3984        GetWebRenderUserData<WebRenderAnimationData>(aFrame,
   3985                                                     (uint32_t)aDisplayItemKey);
   3986    if (animationData) {
   3987      aWebRenderBridgeChild->SendGetAnimationValue(
   3988          animationData->GetAnimationInfo().GetCompositorAnimationsId(),
   3989          &value);
   3990    }
   3991  }
   3992  return value;
   3993 }
   3994 
   3995 NS_IMETHODIMP
   3996 nsDOMWindowUtils::GetOMTAStyle(Element* aElement, const nsAString& aProperty,
   3997                               const nsAString& aPseudoElement,
   3998                               nsAString& aResult) {
   3999  if (!aElement) {
   4000    return NS_ERROR_INVALID_ARG;
   4001  }
   4002 
   4003  auto frameOrError = GetTargetFrame(aElement, aPseudoElement);
   4004  if (frameOrError.isErr()) {
   4005    return frameOrError.unwrapErr();
   4006  }
   4007  nsIFrame* frame = frameOrError.unwrap();
   4008 
   4009  RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
   4010  if (frame && nsLayoutUtils::AreAsyncAnimationsEnabled()) {
   4011    if (aProperty.EqualsLiteral("opacity")) {
   4012      OMTAValue value = GetOMTAValue(frame, DisplayItemType::TYPE_OPACITY,
   4013                                     GetWebRenderBridge());
   4014      if (value.type() == OMTAValue::Tfloat) {
   4015        cssValue = new nsROCSSPrimitiveValue;
   4016        cssValue->SetNumber(value.get_float());
   4017      }
   4018    } else if (aProperty.EqualsLiteral("transform") ||
   4019               aProperty.EqualsLiteral("translate") ||
   4020               aProperty.EqualsLiteral("rotate") ||
   4021               aProperty.EqualsLiteral("scale") ||
   4022               aProperty.EqualsLiteral("offset-path") ||
   4023               aProperty.EqualsLiteral("offset-distance") ||
   4024               aProperty.EqualsLiteral("offset-rotate") ||
   4025               aProperty.EqualsLiteral("offset-anchor") ||
   4026               aProperty.EqualsLiteral("offset-position")) {
   4027      OMTAValue value = GetOMTAValue(frame, DisplayItemType::TYPE_TRANSFORM,
   4028                                     GetWebRenderBridge());
   4029      if (value.type() == OMTAValue::TMatrix4x4) {
   4030        cssValue = nsComputedDOMStyle::MatrixToCSSValue(value.get_Matrix4x4());
   4031      }
   4032    } else if (aProperty.EqualsLiteral("background-color")) {
   4033      OMTAValue value = GetOMTAValue(
   4034          frame, DisplayItemType::TYPE_BACKGROUND_COLOR, GetWebRenderBridge());
   4035      if (value.type() == OMTAValue::Tnscolor) {
   4036        nsStyleUtil::GetSerializedColorValue(value.get_nscolor(), aResult);
   4037        return NS_OK;
   4038      }
   4039    }
   4040  }
   4041 
   4042  if (cssValue) {
   4043    cssValue->GetCssText(aResult);
   4044    return NS_OK;
   4045  }
   4046  aResult.Truncate();
   4047  return NS_OK;
   4048 }
   4049 
   4050 namespace {
   4051 
   4052 class HandlingUserInputHelper final : public nsIJSRAIIHelper {
   4053 public:
   4054  explicit HandlingUserInputHelper(bool aHandlingUserInput);
   4055 
   4056  NS_DECL_ISUPPORTS
   4057  NS_DECL_NSIJSRAIIHELPER
   4058 
   4059 private:
   4060  ~HandlingUserInputHelper();
   4061 
   4062  bool mHandlingUserInput;
   4063  bool mDestructCalled = false;
   4064 };
   4065 
   4066 NS_IMPL_ISUPPORTS(HandlingUserInputHelper, nsIJSRAIIHelper)
   4067 
   4068 HandlingUserInputHelper::HandlingUserInputHelper(bool aHandlingUserInput)
   4069    : mHandlingUserInput(aHandlingUserInput) {
   4070  if (aHandlingUserInput) {
   4071    UserActivation::StartHandlingUserInput(eVoidEvent);
   4072  }
   4073 }
   4074 
   4075 HandlingUserInputHelper::~HandlingUserInputHelper() {
   4076  // We assert, but just in case, make sure we notify the ESM.
   4077  MOZ_ASSERT(mDestructCalled);
   4078  if (!mDestructCalled) {
   4079    Destruct();
   4080  }
   4081 }
   4082 
   4083 NS_IMETHODIMP
   4084 HandlingUserInputHelper::Destruct() {
   4085  if (NS_WARN_IF(mDestructCalled)) {
   4086    return NS_ERROR_FAILURE;
   4087  }
   4088 
   4089  mDestructCalled = true;
   4090  if (mHandlingUserInput) {
   4091    UserActivation::StopHandlingUserInput(eVoidEvent);
   4092  }
   4093 
   4094  return NS_OK;
   4095 }
   4096 
   4097 }  // unnamed namespace
   4098 
   4099 NS_IMETHODIMP
   4100 nsDOMWindowUtils::SetHandlingUserInput(bool aHandlingUserInput,
   4101                                       nsIJSRAIIHelper** aHelper) {
   4102  if (aHandlingUserInput) {
   4103    if (Document* doc = GetDocument()) {
   4104      doc->NotifyUserGestureActivation();
   4105    }
   4106  }
   4107  auto helper = MakeRefPtr<HandlingUserInputHelper>(aHandlingUserInput);
   4108  helper.forget(aHelper);
   4109  return NS_OK;
   4110 }
   4111 
   4112 NS_IMETHODIMP
   4113 nsDOMWindowUtils::IsKeyboardEventUserActivity(Event* aEvent, bool* aResult) {
   4114  NS_ENSURE_STATE(aEvent);
   4115  if (!aEvent->AsKeyboardEvent()) {
   4116    return NS_ERROR_INVALID_ARG;
   4117  }
   4118 
   4119  WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
   4120  NS_ENSURE_STATE(internalEvent);
   4121  *aResult = EventStateManager::IsKeyboardEventUserActivity(internalEvent);
   4122  return NS_OK;
   4123 }
   4124 
   4125 NS_IMETHODIMP
   4126 nsDOMWindowUtils::GetContentAPZTestData(
   4127    Element* aElement, JSContext* aContext,
   4128    JS::MutableHandle<JS::Value> aOutContentTestData) {
   4129  if (nsIWidget* widget = GetWidgetForElement(aElement)) {
   4130    WindowRenderer* renderer = widget->GetWindowRenderer();
   4131    if (!renderer) {
   4132      return NS_OK;
   4133    }
   4134    if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
   4135      if (!wr->GetAPZTestData().ToJS(aOutContentTestData, aContext)) {
   4136        return NS_ERROR_FAILURE;
   4137      }
   4138    }
   4139  }
   4140 
   4141  return NS_OK;
   4142 }
   4143 
   4144 NS_IMETHODIMP
   4145 nsDOMWindowUtils::GetCompositorAPZTestData(
   4146    Element* aElement, JSContext* aContext,
   4147    JS::MutableHandle<JS::Value> aOutCompositorTestData) {
   4148  if (nsIWidget* widget = GetWidgetForElement(aElement)) {
   4149    WindowRenderer* renderer = widget->GetWindowRenderer();
   4150    if (!renderer) {
   4151      return NS_OK;
   4152    }
   4153    APZTestData compositorSideData;
   4154    if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
   4155      if (!wr->WrBridge()) {
   4156        return NS_ERROR_UNEXPECTED;
   4157      }
   4158      if (!wr->WrBridge()->SendGetAPZTestData(&compositorSideData)) {
   4159        return NS_ERROR_FAILURE;
   4160      }
   4161    }
   4162    if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) {
   4163      return NS_ERROR_FAILURE;
   4164    }
   4165  }
   4166 
   4167  return NS_OK;
   4168 }
   4169 
   4170 NS_IMETHODIMP
   4171 nsDOMWindowUtils::PostRestyleSelfEvent(Element* aElement) {
   4172  if (!aElement) {
   4173    return NS_ERROR_INVALID_ARG;
   4174  }
   4175 
   4176  nsLayoutUtils::PostRestyleEvent(aElement, RestyleHint::RESTYLE_SELF,
   4177                                  nsChangeHint(0));
   4178  return NS_OK;
   4179 }
   4180 
   4181 NS_IMETHODIMP
   4182 nsDOMWindowUtils::SetCustomTitlebar(bool aCustomTitlebar) {
   4183  // TODO(emilio): Can't we use nsDOMWindowUtils::GetWidget()?
   4184  if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow)) {
   4185    if (nsCOMPtr<nsIBaseWindow> baseWindow =
   4186            do_QueryInterface(window->GetDocShell())) {
   4187      if (nsCOMPtr<nsIWidget> widget = baseWindow->GetMainWidget()) {
   4188        widget->SetCustomTitlebar(aCustomTitlebar);
   4189      }
   4190    }
   4191  }
   4192  return NS_OK;
   4193 }
   4194 
   4195 NS_IMETHODIMP
   4196 nsDOMWindowUtils::SetResizeMargin(int32_t aResizeMargin) {
   4197  // TODO(emilio): Can't we use nsDOMWindowUtils::GetWidget()?
   4198  if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow)) {
   4199    if (nsCOMPtr<nsIBaseWindow> baseWindow =
   4200            do_QueryInterface(window->GetDocShell())) {
   4201      if (nsCOMPtr<nsIWidget> widget = baseWindow->GetMainWidget()) {
   4202        CSSToLayoutDeviceScale scaleFactor = widget->GetDefaultScale();
   4203        widget->SetResizeMargin(
   4204            (CSSCoord(float(aResizeMargin)) * scaleFactor).Rounded());
   4205      }
   4206    }
   4207  }
   4208 
   4209  return NS_OK;
   4210 }
   4211 
   4212 NS_IMETHODIMP
   4213 nsDOMWindowUtils::GetFrameUniformityTestData(
   4214    JSContext* aContext, JS::MutableHandle<JS::Value> aOutFrameUniformity) {
   4215  nsIWidget* widget = GetWidget();
   4216  if (!widget) {
   4217    return NS_ERROR_NOT_AVAILABLE;
   4218  }
   4219 
   4220  WindowRenderer* renderer = widget->GetWindowRenderer();
   4221  if (!renderer) {
   4222    return NS_ERROR_NOT_AVAILABLE;
   4223  }
   4224 
   4225  FrameUniformityData outData;
   4226  renderer->GetFrameUniformity(&outData);
   4227  outData.ToJS(aOutFrameUniformity, aContext);
   4228  return NS_OK;
   4229 }
   4230 
   4231 NS_IMETHODIMP
   4232 nsDOMWindowUtils::XpconnectArgument(nsISupports* aObj) {
   4233  // Do nothing.
   4234  return NS_OK;
   4235 }
   4236 
   4237 NS_IMETHODIMP
   4238 nsDOMWindowUtils::AskPermission(nsIContentPermissionRequest* aRequest) {
   4239  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   4240  return nsContentPermissionUtils::AskPermission(
   4241      aRequest, window->GetCurrentInnerWindow());
   4242 }
   4243 
   4244 NS_IMETHODIMP
   4245 nsDOMWindowUtils::GetRestyleGeneration(uint64_t* aResult) {
   4246  nsPresContext* presContext = GetPresContext();
   4247  if (!presContext) {
   4248    return NS_ERROR_NOT_AVAILABLE;
   4249  }
   4250 
   4251  *aResult = presContext->GetRestyleGeneration();
   4252  return NS_OK;
   4253 }
   4254 
   4255 NS_IMETHODIMP
   4256 nsDOMWindowUtils::GetFramesConstructed(uint64_t* aResult) {
   4257  nsPresContext* presContext = GetPresContext();
   4258  if (!presContext) {
   4259    return NS_ERROR_NOT_AVAILABLE;
   4260  }
   4261 
   4262  *aResult = presContext->FramesConstructedCount();
   4263  return NS_OK;
   4264 }
   4265 
   4266 NS_IMETHODIMP
   4267 nsDOMWindowUtils::GetFramesReflowed(uint64_t* aResult) {
   4268  nsPresContext* presContext = GetPresContext();
   4269  if (!presContext) {
   4270    return NS_ERROR_NOT_AVAILABLE;
   4271  }
   4272 
   4273  *aResult = presContext->FramesReflowedCount();
   4274  return NS_OK;
   4275 }
   4276 
   4277 NS_IMETHODIMP
   4278 nsDOMWindowUtils::GetAnimationTriggeredRestyles(uint64_t* aResult) {
   4279  nsPresContext* presContext = GetPresContext();
   4280  if (!presContext) {
   4281    return NS_ERROR_NOT_AVAILABLE;
   4282  }
   4283 
   4284  *aResult = presContext->AnimationTriggeredRestylesCount();
   4285  return NS_OK;
   4286 }
   4287 
   4288 NS_IMETHODIMP
   4289 nsDOMWindowUtils::GetRefreshDriverHasPendingTick(bool* aResult) {
   4290  nsPresContext* presContext = GetPresContext();
   4291  if (!presContext) {
   4292    return NS_ERROR_NOT_AVAILABLE;
   4293  }
   4294 
   4295  *aResult = presContext->RefreshDriver()->HasPendingTick();
   4296  return NS_OK;
   4297 }
   4298 
   4299 NS_IMETHODIMP
   4300 nsDOMWindowUtils::EnterChaosMode() {
   4301  ChaosMode::enterChaosMode();
   4302  return NS_OK;
   4303 }
   4304 
   4305 NS_IMETHODIMP
   4306 nsDOMWindowUtils::LeaveChaosMode() {
   4307  ChaosMode::leaveChaosMode();
   4308  return NS_OK;
   4309 }
   4310 
   4311 NS_IMETHODIMP
   4312 nsDOMWindowUtils::TriggerDeviceReset() {
   4313  if (!XRE_IsParentProcess()) {
   4314    return NS_ERROR_NOT_AVAILABLE;
   4315  }
   4316 
   4317  GPUProcessManager* pm = GPUProcessManager::Get();
   4318  if (pm) {
   4319    pm->SimulateDeviceReset();
   4320  }
   4321  return NS_OK;
   4322 }
   4323 
   4324 NS_IMETHODIMP
   4325 nsDOMWindowUtils::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
   4326                                                          bool* aRetVal) {
   4327  PresShell* presShell = GetPresShell();
   4328  if (!presShell) {
   4329    return NS_ERROR_FAILURE;
   4330  }
   4331 
   4332  return presShell->HasRuleProcessorUsedByMultipleStyleSets(aSheetType,
   4333                                                            aRetVal);
   4334 }
   4335 
   4336 NS_IMETHODIMP
   4337 nsDOMWindowUtils::RespectDisplayPortSuppression(bool aEnabled) {
   4338  RefPtr<PresShell> presShell = GetPresShell();
   4339  presShell->RespectDisplayportSuppression(aEnabled);
   4340  return NS_OK;
   4341 }
   4342 
   4343 NS_IMETHODIMP
   4344 nsDOMWindowUtils::ForceReflowInterrupt() {
   4345  nsPresContext* pc = GetPresContext();
   4346  if (!pc) {
   4347    return NS_ERROR_NOT_AVAILABLE;
   4348  }
   4349  pc->SetPendingInterruptFromTest();
   4350  return NS_OK;
   4351 }
   4352 
   4353 NS_IMETHODIMP
   4354 nsDOMWindowUtils::TerminateGPUProcess() {
   4355  GPUProcessManager* pm = GPUProcessManager::Get();
   4356  if (pm) {
   4357    pm->KillProcess();
   4358  }
   4359  return NS_OK;
   4360 }
   4361 
   4362 NS_IMETHODIMP
   4363 nsDOMWindowUtils::GetGpuProcessPid(int32_t* aPid) {
   4364  GPUProcessManager* pm = GPUProcessManager::Get();
   4365  if (pm) {
   4366    *aPid = pm->GPUProcessPid();
   4367  } else {
   4368    *aPid = -1;
   4369  }
   4370 
   4371  return NS_OK;
   4372 }
   4373 
   4374 NS_IMETHODIMP
   4375 nsDOMWindowUtils::GetRddProcessPid(int32_t* aPid) {
   4376  RDDProcessManager* pm = RDDProcessManager::Get();
   4377  if (pm) {
   4378    *aPid = pm->RDDProcessPid();
   4379  } else {
   4380    *aPid = -1;
   4381  }
   4382 
   4383  return NS_OK;
   4384 }
   4385 
   4386 struct StateTableEntry {
   4387  const char* mStateString;
   4388  ElementState mState;
   4389 };
   4390 
   4391 NS_IMETHODIMP
   4392 nsDOMWindowUtils::GetStorageUsage(Storage* aStorage, int64_t* aRetval) {
   4393  if (!aStorage) {
   4394    return NS_ERROR_UNEXPECTED;
   4395  }
   4396 
   4397  *aRetval = aStorage->GetOriginQuotaUsage();
   4398 
   4399  return NS_OK;
   4400 }
   4401 
   4402 NS_IMETHODIMP
   4403 nsDOMWindowUtils::GetDirectionFromText(const nsAString& aString,
   4404                                       int32_t* aRetval) {
   4405  Directionality dir =
   4406      ::GetDirectionFromText(aString.BeginReading(), aString.Length(), nullptr);
   4407  switch (dir) {
   4408    case Directionality::Unset:
   4409      *aRetval = nsIDOMWindowUtils::DIRECTION_NOT_SET;
   4410      break;
   4411    case Directionality::Rtl:
   4412      *aRetval = nsIDOMWindowUtils::DIRECTION_RTL;
   4413      break;
   4414    case Directionality::Ltr:
   4415      *aRetval = nsIDOMWindowUtils::DIRECTION_LTR;
   4416      break;
   4417    case Directionality::Auto:
   4418      MOZ_ASSERT_UNREACHABLE(
   4419          "GetDirectionFromText should never return this value");
   4420      return NS_ERROR_FAILURE;
   4421  }
   4422  return NS_OK;
   4423 }
   4424 
   4425 NS_IMETHODIMP
   4426 nsDOMWindowUtils::EnsureDirtyRootFrame() {
   4427  Document* doc = GetDocument();
   4428  PresShell* presShell = doc ? doc->GetPresShell() : nullptr;
   4429 
   4430  if (!presShell) {
   4431    return NS_ERROR_FAILURE;
   4432  }
   4433 
   4434  nsIFrame* frame = presShell->GetRootFrame();
   4435  if (!frame) {
   4436    return NS_ERROR_FAILURE;
   4437  }
   4438 
   4439  presShell->FrameNeedsReflow(
   4440      frame, IntrinsicDirty::FrameAncestorsAndDescendants, NS_FRAME_IS_DIRTY);
   4441  return NS_OK;
   4442 }
   4443 
   4444 NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
   4445  NS_INTERFACE_MAP_ENTRY(nsISupports)
   4446  NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)
   4447 NS_INTERFACE_MAP_END
   4448 
   4449 NS_IMPL_ADDREF(nsTranslationNodeList)
   4450 NS_IMPL_RELEASE(nsTranslationNodeList)
   4451 
   4452 NS_IMETHODIMP
   4453 nsTranslationNodeList::Item(uint32_t aIndex, nsINode** aRetVal) {
   4454  NS_ENSURE_ARG_POINTER(aRetVal);
   4455  NS_IF_ADDREF(*aRetVal = mNodes.SafeElementAt(aIndex));
   4456  return NS_OK;
   4457 }
   4458 
   4459 NS_IMETHODIMP
   4460 nsTranslationNodeList::IsTranslationRootAtIndex(uint32_t aIndex,
   4461                                                bool* aRetVal) {
   4462  NS_ENSURE_ARG_POINTER(aRetVal);
   4463  if (aIndex >= mLength) {
   4464    *aRetVal = false;
   4465    return NS_OK;
   4466  }
   4467 
   4468  *aRetVal = mNodeIsRoot.ElementAt(aIndex);
   4469  return NS_OK;
   4470 }
   4471 
   4472 NS_IMETHODIMP
   4473 nsTranslationNodeList::GetLength(uint32_t* aRetVal) {
   4474  NS_ENSURE_ARG_POINTER(aRetVal);
   4475  *aRetVal = mLength;
   4476  return NS_OK;
   4477 }
   4478 
   4479 NS_IMETHODIMP
   4480 nsDOMWindowUtils::WrCapture() {
   4481  if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
   4482    wrbc->Capture();
   4483  }
   4484  return NS_OK;
   4485 }
   4486 
   4487 NS_IMETHODIMP
   4488 nsDOMWindowUtils::WrStartCaptureSequence(const nsACString& aPath,
   4489                                         uint32_t aFlags) {
   4490  if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
   4491    wrbc->StartCaptureSequence(nsCString(aPath), aFlags);
   4492  }
   4493  return NS_OK;
   4494 }
   4495 
   4496 NS_IMETHODIMP
   4497 nsDOMWindowUtils::WrStopCaptureSequence() {
   4498  if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
   4499    wrbc->StopCaptureSequence();
   4500  }
   4501  return NS_OK;
   4502 }
   4503 
   4504 NS_IMETHODIMP
   4505 nsDOMWindowUtils::SetCompositionRecording(bool aValue, Promise** aOutPromise) {
   4506  return aValue ? StartCompositionRecording(aOutPromise)
   4507                : StopCompositionRecording(true, aOutPromise);
   4508 }
   4509 
   4510 NS_IMETHODIMP
   4511 nsDOMWindowUtils::StartCompositionRecording(Promise** aOutPromise) {
   4512  NS_ENSURE_ARG(aOutPromise);
   4513  *aOutPromise = nullptr;
   4514 
   4515  nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow);
   4516  NS_ENSURE_STATE(outer);
   4517  nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
   4518  NS_ENSURE_STATE(inner);
   4519 
   4520  ErrorResult err;
   4521  RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err);
   4522  if (NS_WARN_IF(err.Failed())) {
   4523    return err.StealNSResult();
   4524  }
   4525 
   4526  CompositorBridgeChild* cbc = GetCompositorBridge();
   4527  if (NS_WARN_IF(!cbc)) {
   4528    promise->MaybeReject(NS_ERROR_UNEXPECTED);
   4529  } else {
   4530    cbc->SendBeginRecording(TimeStamp::Now())
   4531        ->Then(
   4532            GetCurrentSerialEventTarget(), __func__,
   4533            [promise](const bool& aSuccess) {
   4534              if (aSuccess) {
   4535                promise->MaybeResolve(true);
   4536              } else {
   4537                promise->MaybeRejectWithInvalidStateError(
   4538                    "The composition recorder is already running.");
   4539              }
   4540            },
   4541            [promise](const mozilla::ipc::ResponseRejectReason&) {
   4542              promise->MaybeRejectWithInvalidStateError(
   4543                  "Could not start the composition recorder.");
   4544            });
   4545  }
   4546 
   4547  promise.forget(aOutPromise);
   4548  return NS_OK;
   4549 }
   4550 
   4551 static bool WriteRecordingToDisk(const FrameRecording& aRecording,
   4552                                 double aUnixStartMS) {
   4553  // The directory name contains the unix timestamp for when recording started,
   4554  // because we want the consumer of these files to be able to compute an
   4555  // absolute timestamp of each screenshot. That allows them to align
   4556  // screenshots with timed data from other sources, such as Gecko profiler
   4557  // information. The time of each screenshot is part of the screenshot's
   4558  // filename, expressed as milliseconds from the recording start.
   4559  std::stringstream recordingDirectory;
   4560  recordingDirectory << gfxVars::LayersWindowRecordingPath()
   4561                     << "windowrecording-" << int64_t(aUnixStartMS);
   4562 
   4563 #ifdef XP_WIN
   4564  _mkdir(recordingDirectory.str().c_str());
   4565 #else
   4566  mkdir(recordingDirectory.str().c_str(), 0777);
   4567 #endif
   4568 
   4569  auto byteSpan = aRecording.bytes().AsSpan();
   4570 
   4571  uint32_t i = 1;
   4572 
   4573  for (const auto& frame : aRecording.frames()) {
   4574    const uint32_t frameBufferLength = frame.length();
   4575    if (frameBufferLength > byteSpan.Length()) {
   4576      return false;
   4577    }
   4578 
   4579    const auto frameSpan = byteSpan.To(frameBufferLength);
   4580    byteSpan = byteSpan.From(frameBufferLength);
   4581 
   4582    const double frameTimeMS =
   4583        (frame.timeOffset() - aRecording.startTime()).ToMilliseconds();
   4584 
   4585    std::stringstream filename;
   4586    filename << recordingDirectory.str() << "/frame-" << i << "-"
   4587             << uint32_t(frameTimeMS) << ".png";
   4588 
   4589    FILE* file = fopen(filename.str().c_str(), "wb");
   4590    if (!file) {
   4591      return false;
   4592    }
   4593 
   4594    const size_t bytesWritten =
   4595        fwrite(frameSpan.Elements(), sizeof(uint8_t), frameSpan.Length(), file);
   4596 
   4597    fclose(file);
   4598 
   4599    if (bytesWritten < frameSpan.Length()) {
   4600      return false;
   4601    }
   4602 
   4603    ++i;
   4604  }
   4605 
   4606  return byteSpan.Length() == 0;
   4607 }
   4608 
   4609 static Maybe<DOMCollectedFrames> ConvertCompositionRecordingFramesToDom(
   4610    const FrameRecording& aRecording, double aUnixStartMS) {
   4611  auto byteSpan = aRecording.bytes().AsSpan();
   4612 
   4613  nsTArray<DOMCollectedFrame> domFrames;
   4614 
   4615  for (const auto& recordedFrame : aRecording.frames()) {
   4616    const uint32_t frameBufferLength = recordedFrame.length();
   4617    if (frameBufferLength > byteSpan.Length()) {
   4618      return Nothing();
   4619    }
   4620 
   4621    const auto frameSpan = byteSpan.To(frameBufferLength);
   4622    byteSpan = byteSpan.From(frameBufferLength);
   4623 
   4624    nsCString dataUri;
   4625 
   4626    dataUri.AppendLiteral("data:image/png;base64,");
   4627 
   4628    nsresult rv =
   4629        Base64EncodeAppend(reinterpret_cast<const char*>(frameSpan.Elements()),
   4630                           frameSpan.Length(), dataUri);
   4631    if (NS_FAILED(rv)) {
   4632      return Nothing();
   4633    }
   4634 
   4635    DOMCollectedFrame domFrame;
   4636    domFrame.mTimeOffset =
   4637        (recordedFrame.timeOffset() - aRecording.startTime()).ToMilliseconds();
   4638    domFrame.mDataUri = std::move(dataUri);
   4639 
   4640    domFrames.AppendElement(std::move(domFrame));
   4641  }
   4642 
   4643  if (byteSpan.Length() != 0) {
   4644    return Nothing();
   4645  }
   4646 
   4647  DOMCollectedFrames result;
   4648 
   4649  result.mRecordingStart = aUnixStartMS;
   4650  result.mFrames = std::move(domFrames);
   4651 
   4652  return Some(std::move(result));
   4653 }
   4654 
   4655 NS_IMETHODIMP
   4656 nsDOMWindowUtils::StopCompositionRecording(bool aWriteToDisk,
   4657                                           Promise** aOutPromise) {
   4658  NS_ENSURE_ARG_POINTER(aOutPromise);
   4659  *aOutPromise = nullptr;
   4660 
   4661  nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow);
   4662  NS_ENSURE_STATE(outer);
   4663  nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
   4664  NS_ENSURE_STATE(inner);
   4665 
   4666  ErrorResult err;
   4667  RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err);
   4668  if (NS_WARN_IF(err.Failed())) {
   4669    return err.StealNSResult();
   4670  }
   4671 
   4672  RefPtr<Promise>(promise).forget(aOutPromise);
   4673 
   4674  CompositorBridgeChild* cbc = GetCompositorBridge();
   4675  if (NS_WARN_IF(!cbc)) {
   4676    promise->MaybeReject(NS_ERROR_UNEXPECTED);
   4677    return NS_OK;
   4678  }
   4679 
   4680  cbc->SendEndRecording()->Then(
   4681      GetCurrentSerialEventTarget(), __func__,
   4682      [promise, aWriteToDisk](Maybe<FrameRecording>&& aRecording) {
   4683        if (!aRecording) {
   4684          promise->MaybeRejectWithUnknownError("Failed to get frame recording");
   4685          return;
   4686        }
   4687 
   4688        // We need to know when the recording started in Unix Time.
   4689        // Unfortunately, the recording start time is an opaque Timestamp that
   4690        // can only be used to calculate a duration.
   4691        //
   4692        // This is not great, but we are going to get Now() twice in close
   4693        // proximity, one in Unix Time and the other in Timestamp time. Then we
   4694        // can subtract the length of the recording from the current Unix Time
   4695        // to get the Unix start time.
   4696        const TimeStamp timestampNow = TimeStamp::Now();
   4697        const int64_t unixNowUS = PR_Now();
   4698 
   4699        const TimeDuration recordingLength =
   4700            timestampNow - aRecording->startTime();
   4701        const double unixNowMS = double(unixNowUS) / 1000.0;
   4702        const double unixStartMS = unixNowMS - recordingLength.ToMilliseconds();
   4703 
   4704        if (aWriteToDisk) {
   4705          if (!WriteRecordingToDisk(*aRecording, unixStartMS)) {
   4706            promise->MaybeRejectWithUnknownError(
   4707                "Failed to write recording to disk");
   4708            return;
   4709          }
   4710          promise->MaybeResolveWithUndefined();
   4711        } else {
   4712          auto maybeDomFrames =
   4713              ConvertCompositionRecordingFramesToDom(*aRecording, unixStartMS);
   4714          if (!maybeDomFrames) {
   4715            promise->MaybeRejectWithUnknownError(
   4716                "Unable to base64-encode recorded frames");
   4717            return;
   4718          }
   4719          promise->MaybeResolve(*maybeDomFrames);
   4720        }
   4721      },
   4722      [promise](const mozilla::ipc::ResponseRejectReason&) {
   4723        promise->MaybeRejectWithUnknownError(
   4724            "IPC failed getting composition recording");
   4725      });
   4726 
   4727  return NS_OK;
   4728 }
   4729 
   4730 NS_IMETHODIMP
   4731 nsDOMWindowUtils::SetSystemFont(const nsACString& aFontName) {
   4732  nsIWidget* widget = GetWidget();
   4733  if (!widget) {
   4734    return NS_OK;
   4735  }
   4736 
   4737  nsAutoCString fontName(aFontName);
   4738  return widget->SetSystemFont(fontName);
   4739 }
   4740 
   4741 NS_IMETHODIMP
   4742 nsDOMWindowUtils::GetSystemFont(nsACString& aFontName) {
   4743  nsIWidget* widget = GetWidget();
   4744  if (!widget) {
   4745    return NS_OK;
   4746  }
   4747 
   4748  nsAutoCString fontName;
   4749  widget->GetSystemFont(fontName);
   4750  aFontName.Assign(fontName);
   4751  return NS_OK;
   4752 }
   4753 
   4754 NS_IMETHODIMP
   4755 nsDOMWindowUtils::IsCssPropertyRecordedInUseCounter(const nsACString& aPropName,
   4756                                                    bool* aRecorded) {
   4757  *aRecorded = false;
   4758 
   4759  Document* doc = GetDocument();
   4760  if (!doc || !doc->GetStyleUseCounters()) {
   4761    return NS_ERROR_FAILURE;
   4762  }
   4763 
   4764  bool knownProp = false;
   4765  *aRecorded = Servo_IsCssPropertyRecordedInUseCounter(
   4766      doc->GetStyleUseCounters(), &aPropName, &knownProp);
   4767  return knownProp ? NS_OK : NS_ERROR_FAILURE;
   4768 }
   4769 
   4770 NS_IMETHODIMP
   4771 nsDOMWindowUtils::IsCoepCredentialless(bool* aResult) {
   4772  Document* doc = GetDocument();
   4773  if (!doc) {
   4774    return NS_ERROR_FAILURE;
   4775  }
   4776 
   4777  *aResult = net::IsCoepCredentiallessEnabled(
   4778      doc->Trials().IsEnabled(OriginTrial::CoepCredentialless));
   4779  return NS_OK;
   4780 }
   4781 
   4782 NS_IMETHODIMP
   4783 nsDOMWindowUtils::GetLayersId(Element* aElement, uint64_t* aOutLayersId) {
   4784  nsIWidget* widget = GetWidgetForElement(aElement);
   4785  if (!widget) {
   4786    return NS_ERROR_FAILURE;
   4787  }
   4788  *aOutLayersId = (uint64_t)widget->GetLayersId();
   4789  return NS_OK;
   4790 }
   4791 
   4792 NS_IMETHODIMP
   4793 nsDOMWindowUtils::GetPaintCount(uint64_t* aPaintCount) {
   4794  auto* presShell = GetPresShell();
   4795  *aPaintCount = presShell ? presShell->GetPaintCount() : 0;
   4796  return NS_OK;
   4797 }
   4798 
   4799 NS_IMETHODIMP
   4800 nsDOMWindowUtils::GetWebrtcRawDeviceId(nsAString& aRawDeviceId) {
   4801  if (!XRE_IsParentProcess()) {
   4802    MOZ_CRASH(
   4803        "GetWebrtcRawDeviceId is only available in the parent "
   4804        "process");
   4805  }
   4806 
   4807  nsIWidget* widget = GetWidget();
   4808  if (!widget) {
   4809    return NS_ERROR_FAILURE;
   4810  }
   4811 
   4812  int64_t rawDeviceId =
   4813      (int64_t)(widget->GetNativeData(NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID));
   4814  if (!rawDeviceId) {
   4815    return NS_ERROR_FAILURE;
   4816  }
   4817 
   4818  aRawDeviceId.AppendInt(rawDeviceId);
   4819  return NS_OK;
   4820 }
   4821 
   4822 NS_IMETHODIMP
   4823 nsDOMWindowUtils::GetEffectivelyThrottlesFrameRequests(bool* aResult) {
   4824  Document* doc = GetDocument();
   4825  if (!doc) {
   4826    return NS_ERROR_FAILURE;
   4827  }
   4828  *aResult = doc->IsRenderingSuppressed() || doc->ShouldThrottleFrameRequests();
   4829  return NS_OK;
   4830 }
   4831 
   4832 NS_IMETHODIMP
   4833 nsDOMWindowUtils::ResetMobileViewportManager() {
   4834  if (RefPtr<PresShell> presShell = GetPresShell()) {
   4835    if (auto mvm = presShell->GetMobileViewportManager()) {
   4836      mvm->SetInitialViewport();
   4837      return NS_OK;
   4838    }
   4839  }
   4840  // Unable to reset, so let's error out
   4841  return NS_ERROR_FAILURE;
   4842 }
   4843 
   4844 NS_IMETHODIMP
   4845 nsDOMWindowUtils::GetSuspendedByBrowsingContextGroup(bool* aResult) {
   4846  nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   4847  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   4848 
   4849  nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
   4850  NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE);
   4851 
   4852  *aResult = inner->GetWasSuspendedByGroup();
   4853  return NS_OK;
   4854 }
   4855 
   4856 NS_IMETHODIMP
   4857 nsDOMWindowUtils::GetHasScrollLinkedEffect(bool* aResult) {
   4858  Document* doc = GetDocument();
   4859  if (!doc) {
   4860    return NS_ERROR_FAILURE;
   4861  }
   4862  *aResult = doc->HasScrollLinkedEffect();
   4863  return NS_OK;
   4864 }
   4865 
   4866 NS_IMETHODIMP
   4867 nsDOMWindowUtils::GetOrientationLock(uint32_t* aOrientationLock) {
   4868  NS_WARNING("nsDOMWindowUtils::GetOrientationLock");
   4869 
   4870  nsIDocShell* docShell = GetDocShell();
   4871  if (!docShell) {
   4872    return NS_ERROR_FAILURE;
   4873  }
   4874 
   4875  BrowsingContext* bc = docShell->GetBrowsingContext();
   4876  bc = bc ? bc->Top() : nullptr;
   4877  if (!bc) {
   4878    return NS_ERROR_FAILURE;
   4879  }
   4880 
   4881  *aOrientationLock = static_cast<uint32_t>(bc->GetOrientationLock());
   4882  return NS_OK;
   4883 }
   4884 
   4885 NS_IMETHODIMP
   4886 nsDOMWindowUtils::GetWheelScrollTarget(Element** aResult) {
   4887  *aResult = nullptr;
   4888  if (nsIFrame* targetFrame = WheelTransaction::GetScrollTargetFrame()) {
   4889    NS_IF_ADDREF(*aResult = Element::FromNodeOrNull(targetFrame->GetContent()));
   4890  }
   4891  return NS_OK;
   4892 }
   4893 
   4894 NS_IMETHODIMP
   4895 nsDOMWindowUtils::SetHiDPIMode(bool aHiDPI) {
   4896 #ifdef DEBUG
   4897  nsCOMPtr<nsIWidget> widget = GetWidget();
   4898  if (!widget) return NS_ERROR_FAILURE;
   4899 
   4900  return widget->SetHiDPIMode(aHiDPI);
   4901 #else
   4902  return NS_ERROR_NOT_AVAILABLE;
   4903 #endif
   4904 }
   4905 
   4906 NS_IMETHODIMP
   4907 nsDOMWindowUtils::RestoreHiDPIMode() {
   4908 #ifdef DEBUG
   4909  nsCOMPtr<nsIWidget> widget = GetWidget();
   4910  if (!widget) return NS_ERROR_FAILURE;
   4911 
   4912  return widget->RestoreHiDPIMode();
   4913 #else
   4914  return NS_ERROR_NOT_AVAILABLE;
   4915 #endif
   4916 }
   4917 
   4918 NS_IMETHODIMP
   4919 nsDOMWindowUtils::GetDragSession(nsIDragSession** aSession) {
   4920  RefPtr<nsIDragSession> session = nsContentUtils::GetDragSession(GetWidget());
   4921  session.forget(aSession);
   4922  return NS_OK;
   4923 }
   4924 
   4925 NS_IMETHODIMP
   4926 nsDOMWindowUtils::SendMozMouseHitTestEvent(float aX, float aY,
   4927                                           Element* aElement) {
   4928  RefPtr<PresShell> presShell = GetPresShell();
   4929  nsPoint offset;
   4930  RefPtr<nsIWidget> widget = GetWidgetForElement(aElement, &offset);
   4931  LayoutDeviceIntPoint refPoint = nsContentUtils::ToWidgetPoint(
   4932      CSSPoint(aX, aY), offset, presShell->GetPresContext());
   4933 
   4934  SynthesizeMouseEventOptions options;
   4935  options.mIgnoreRootScrollFrame = true;
   4936  options.mIsDOMEventSynthesized = true;
   4937  options.mIsWidgetEventSynthesized = true;
   4938  options.mIsAsyncEnabled = false;
   4939 
   4940  auto result = nsContentUtils::SynthesizeMouseEvent(
   4941      presShell, widget, u"MozMouseHittest"_ns, refPoint,
   4942      SynthesizeMouseEventData{}, options,
   4943      Optional<OwningNonNull<VoidFunction>>{});
   4944  return result.isOk() ? NS_OK : result.unwrapErr();
   4945 }
   4946 
   4947 NS_IMETHODIMP
   4948 nsDOMWindowUtils::GetMicroTaskLevel(uint32_t* aLevel) {
   4949  CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
   4950  NS_ENSURE_STATE(ccjs);
   4951  *aLevel = ccjs->MicroTaskLevel();
   4952  return NS_OK;
   4953 }
   4954 
   4955 NS_IMETHODIMP
   4956 nsDOMWindowUtils::SetMicroTaskLevel(uint32_t aLevel) {
   4957  CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
   4958  NS_ENSURE_STATE(ccjs);
   4959  ccjs->SetMicroTaskLevel(aLevel);
   4960  return NS_OK;
   4961 }