Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / base / nsDOMWindowUtils.cpp
blob9bc8340b9009717e0feecd5c14ff02be07a03daf
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/. */
7 #include "nsDOMWindowUtils.h"
9 #include "LayoutConstants.h"
10 #include "MobileViewportManager.h"
11 #include "mozilla/layers/CompositorBridgeChild.h"
12 #include "nsPresContext.h"
13 #include "nsCaret.h"
14 #include "nsContentList.h"
15 #include "nsError.h"
16 #include "nsQueryContentEventResult.h"
17 #include "nsGlobalWindowOuter.h"
18 #include "nsFocusManager.h"
19 #include "nsFrameManager.h"
20 #include "nsRefreshDriver.h"
21 #include "nsStyleUtil.h"
22 #include "mozilla/Base64.h"
23 #include "mozilla/dom/Animation.h"
24 #include "mozilla/dom/BindingDeclarations.h"
25 #include "mozilla/dom/BlobBinding.h"
26 #include "mozilla/dom/DocumentInlines.h"
27 #include "mozilla/dom/DocumentTimeline.h"
28 #include "mozilla/dom/DOMCollectedFramesBinding.h"
29 #include "mozilla/dom/Event.h"
30 #include "mozilla/dom/Touch.h"
31 #include "mozilla/dom/UserActivation.h"
32 #include "mozilla/EventStateManager.h"
33 #include "mozilla/ServoStyleSet.h"
34 #include "mozilla/SharedStyleSheetCache.h"
35 #include "mozilla/StaticPrefs_test.h"
36 #include "mozilla/InputTaskManager.h"
37 #include "nsIObjectLoadingContent.h"
38 #include "nsIFrame.h"
39 #include "mozilla/layers/APZCCallbackHelper.h"
40 #include "mozilla/layers/PCompositorBridgeTypes.h"
41 #include "mozilla/layers/TouchActionHelper.h"
42 #include "mozilla/media/MediaUtils.h"
43 #include "nsQueryObject.h"
44 #include "CubebDeviceEnumerator.h"
46 #include "nsIScrollableFrame.h"
48 #include "nsContentUtils.h"
50 #include "nsIWidget.h"
51 #include "nsCharsetSource.h"
52 #include "nsJSEnvironment.h"
53 #include "nsJSUtils.h"
54 #include "js/experimental/PCCountProfiling.h" // JS::{Start,Stop}PCCountProfiling, JS::PurgePCCounts, JS::GetPCCountScript{Count,Summary,Contents}
55 #include "js/Object.h" // JS::GetClass
57 #include "mozilla/ChaosMode.h"
58 #include "mozilla/CheckedInt.h"
59 #include "mozilla/MiscEvents.h"
60 #include "mozilla/MouseEvents.h"
61 #include "mozilla/PresShell.h"
62 #include "mozilla/PresShellInlines.h"
63 #include "mozilla/Span.h"
64 #include "mozilla/StaticPrefs_layout.h"
65 #include "mozilla/TextEvents.h"
66 #include "mozilla/TextEventDispatcher.h"
67 #include "mozilla/TouchEvents.h"
69 #include "nsViewManager.h"
71 #include "nsLayoutUtils.h"
72 #include "nsComputedDOMStyle.h"
73 #include "nsCSSProps.h"
74 #include "nsIDocShell.h"
75 #include "mozilla/StyleAnimationValue.h"
76 #include "mozilla/dom/File.h"
77 #include "mozilla/dom/FileBinding.h"
78 #include "mozilla/dom/DOMRect.h"
79 #include <algorithm>
81 #if defined(MOZ_WIDGET_GTK)
82 # include <gdk/gdk.h>
83 # if defined(MOZ_X11)
84 # include <gdk/gdkx.h>
85 # include "X11UndefineNone.h"
86 # endif
87 #endif
89 #include "mozilla/dom/AudioDeviceInfo.h"
90 #include "mozilla/dom/Element.h"
91 #include "mozilla/dom/BrowserChild.h"
92 #include "mozilla/dom/IDBFactoryBinding.h"
93 #include "mozilla/dom/IndexedDatabaseManager.h"
94 #include "mozilla/dom/PermissionMessageUtils.h"
95 #include "mozilla/dom/Text.h"
96 #include "mozilla/dom/quota/PersistenceType.h"
97 #include "mozilla/dom/quota/QuotaManager.h"
98 #include "mozilla/dom/ContentChild.h"
99 #include "mozilla/layers/FrameUniformityData.h"
100 #include "nsPrintfCString.h"
101 #include "nsViewportInfo.h"
102 #include "nsIFormControl.h"
103 // #include "nsWidgetsCID.h"
104 #include "nsDisplayList.h"
105 #include "nsROCSSPrimitiveValue.h"
106 #include "nsIBaseWindow.h"
107 #include "nsIDocShellTreeOwner.h"
108 #include "nsIInterfaceRequestorUtils.h"
109 #include "mozilla/Preferences.h"
110 #include "nsContentPermissionHelper.h"
111 #include "nsCSSPseudoElements.h" // for PseudoStyleType
112 #include "nsNetUtil.h"
113 #include "HTMLImageElement.h"
114 #include "HTMLCanvasElement.h"
115 #include "mozilla/css/ImageLoader.h"
116 #include "mozilla/layers/IAPZCTreeManager.h" // for layers::ZoomToRectBehavior
117 #include "mozilla/dom/Document.h"
118 #include "mozilla/dom/Promise.h"
119 #include "mozilla/ServoBindings.h"
120 #include "mozilla/StyleSheetInlines.h"
121 #include "mozilla/gfx/gfxVars.h"
122 #include "mozilla/gfx/GPUProcessManager.h"
123 #include "mozilla/dom/TimeoutManager.h"
124 #include "mozilla/PreloadedStyleSheet.h"
125 #include "mozilla/ProfilerLabels.h"
126 #include "mozilla/ProfilerMarkers.h"
127 #include "mozilla/layers/WebRenderBridgeChild.h"
128 #include "mozilla/layers/WebRenderLayerManager.h"
129 #include "mozilla/DisplayPortUtils.h"
130 #include "mozilla/ResultExtensions.h"
131 #include "mozilla/ViewportUtils.h"
132 #include "mozilla/dom/BrowsingContextGroup.h"
133 #include "mozilla/IMEStateManager.h"
134 #include "mozilla/IMEContentObserver.h"
135 #include "mozilla/WheelHandlingHelper.h"
136 #include "mozilla/AnimatedPropertyID.h"
138 #ifdef XP_WIN
139 # include <direct.h>
140 #else
141 # include <sys/stat.h>
142 #endif
144 #ifdef XP_WIN
145 # undef GetClassName
146 #endif
148 using namespace mozilla;
149 using namespace mozilla::dom;
150 using namespace mozilla::ipc;
151 using namespace mozilla::layers;
152 using namespace mozilla::widget;
153 using namespace mozilla::gfx;
155 class gfxContext;
157 class OldWindowSize : public LinkedListElement<OldWindowSize> {
158 public:
159 static void Set(nsIWeakReference* aWindowRef, const nsSize& aSize) {
160 OldWindowSize* item = GetItem(aWindowRef);
161 if (item) {
162 item->mSize = aSize;
163 } else {
164 item = new OldWindowSize(aWindowRef, aSize);
165 sList.insertBack(item);
169 static nsSize GetAndRemove(nsIWeakReference* aWindowRef) {
170 nsSize result;
171 if (OldWindowSize* item = GetItem(aWindowRef)) {
172 result = item->mSize;
173 delete item;
175 return result;
178 private:
179 explicit OldWindowSize(nsIWeakReference* aWindowRef, const nsSize& aSize)
180 : mWindowRef(aWindowRef), mSize(aSize) {}
181 ~OldWindowSize() = default;
184 static OldWindowSize* GetItem(nsIWeakReference* aWindowRef) {
185 OldWindowSize* item = sList.getFirst();
186 while (item && item->mWindowRef != aWindowRef) {
187 item = item->getNext();
189 return item;
192 static LinkedList<OldWindowSize> sList;
193 nsWeakPtr mWindowRef;
194 nsSize mSize;
197 namespace {
199 class NativeInputRunnable final : public PrioritizableRunnable {
200 explicit NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent);
201 ~NativeInputRunnable() = default;
203 public:
204 static already_AddRefed<nsIRunnable> Create(
205 already_AddRefed<nsIRunnable>&& aEvent);
208 NativeInputRunnable::NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent)
209 : PrioritizableRunnable(std::move(aEvent),
210 nsIRunnablePriority::PRIORITY_INPUT_HIGH) {}
212 /* static */
213 already_AddRefed<nsIRunnable> NativeInputRunnable::Create(
214 already_AddRefed<nsIRunnable>&& aEvent) {
215 MOZ_ASSERT(NS_IsMainThread());
216 nsCOMPtr<nsIRunnable> event(new NativeInputRunnable(std::move(aEvent)));
217 return event.forget();
220 } // unnamed namespace
222 LinkedList<OldWindowSize> OldWindowSize::sList;
224 NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
225 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWindowUtils)
226 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowUtils)
227 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
228 NS_INTERFACE_MAP_END
230 NS_IMPL_ADDREF(nsDOMWindowUtils)
231 NS_IMPL_RELEASE(nsDOMWindowUtils)
233 nsDOMWindowUtils::nsDOMWindowUtils(nsGlobalWindowOuter* aWindow) {
234 nsCOMPtr<nsISupports> supports = do_QueryObject(aWindow);
235 mWindow = do_GetWeakReference(supports);
238 nsDOMWindowUtils::~nsDOMWindowUtils() { OldWindowSize::GetAndRemove(mWindow); }
240 nsIDocShell* nsDOMWindowUtils::GetDocShell() {
241 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
242 if (!window) {
243 return nullptr;
245 return window->GetDocShell();
248 PresShell* nsDOMWindowUtils::GetPresShell() {
249 nsIDocShell* docShell = GetDocShell();
250 if (!docShell) {
251 return nullptr;
253 return docShell->GetPresShell();
256 nsPresContext* nsDOMWindowUtils::GetPresContext() {
257 nsIDocShell* docShell = GetDocShell();
258 if (!docShell) {
259 return nullptr;
261 return docShell->GetPresContext();
264 Document* nsDOMWindowUtils::GetDocument() {
265 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
266 if (!window) {
267 return nullptr;
269 return window->GetExtantDoc();
272 WebRenderBridgeChild* nsDOMWindowUtils::GetWebRenderBridge() {
273 if (nsIWidget* widget = GetWidget()) {
274 if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
275 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
276 return wr->WrBridge();
280 return nullptr;
283 CompositorBridgeChild* nsDOMWindowUtils::GetCompositorBridge() {
284 if (nsIWidget* widget = GetWidget()) {
285 if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
286 if (CompositorBridgeChild* cbc = renderer->GetCompositorBridgeChild()) {
287 return cbc;
291 return nullptr;
294 NS_IMETHODIMP
295 nsDOMWindowUtils::GetLastOverWindowPointerLocationInCSSPixels(float* aX,
296 float* aY) {
297 const PresShell* presShell = GetPresShell();
298 const nsPresContext* presContext = GetPresContext();
300 if (!presShell || !presContext) {
301 return NS_ERROR_FAILURE;
304 const nsPoint& lastOverWindowPointerLocation =
305 presShell->GetLastOverWindowPointerLocation();
307 if (lastOverWindowPointerLocation.X() == NS_UNCONSTRAINEDSIZE &&
308 lastOverWindowPointerLocation.Y() == NS_UNCONSTRAINEDSIZE) {
309 *aX = 0;
310 *aY = 0;
311 } else {
312 const CSSPoint lastOverWindowPointerLocationInCSSPixels =
313 CSSPoint::FromAppUnits(lastOverWindowPointerLocation);
314 *aX = lastOverWindowPointerLocationInCSSPixels.X();
315 *aY = lastOverWindowPointerLocationInCSSPixels.Y();
318 return NS_OK;
321 NS_IMETHODIMP
322 nsDOMWindowUtils::SyncFlushCompositor() {
323 if (nsIWidget* widget = GetWidget()) {
324 if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
325 if (KnowsCompositor* kc = renderer->AsKnowsCompositor()) {
326 kc->SyncWithCompositor();
330 return NS_OK;
333 NS_IMETHODIMP
334 nsDOMWindowUtils::GetImageAnimationMode(uint16_t* aMode) {
335 NS_ENSURE_ARG_POINTER(aMode);
336 *aMode = 0;
337 nsPresContext* presContext = GetPresContext();
338 if (presContext) {
339 *aMode = presContext->ImageAnimationMode();
340 return NS_OK;
342 return NS_ERROR_NOT_AVAILABLE;
345 NS_IMETHODIMP
346 nsDOMWindowUtils::SetImageAnimationMode(uint16_t aMode) {
347 nsPresContext* presContext = GetPresContext();
348 if (presContext) {
349 presContext->SetImageAnimationMode(aMode);
350 return NS_OK;
352 return NS_ERROR_NOT_AVAILABLE;
355 NS_IMETHODIMP
356 nsDOMWindowUtils::GetDocCharsetIsForced(bool* aIsForced) {
357 *aIsForced = false;
359 Document* doc = GetDocument();
360 if (doc) {
361 auto source = doc->GetDocumentCharacterSetSource();
362 *aIsForced = source == kCharsetFromInitialUserForcedAutoDetection ||
363 source == kCharsetFromFinalUserForcedAutoDetection;
365 return NS_OK;
368 NS_IMETHODIMP
369 nsDOMWindowUtils::GetPhysicalMillimeterInCSSPixels(float* aPhysicalMillimeter) {
370 nsPresContext* presContext = GetPresContext();
371 if (!presContext) {
372 return NS_ERROR_NOT_AVAILABLE;
375 *aPhysicalMillimeter = nsPresContext::AppUnitsToFloatCSSPixels(
376 presContext->PhysicalMillimetersToAppUnits(1));
377 return NS_OK;
380 NS_IMETHODIMP
381 nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName,
382 nsAString& aValue) {
383 Document* doc = GetDocument();
384 if (doc) {
385 RefPtr<nsAtom> name = NS_Atomize(aName);
386 doc->GetHeaderData(name, aValue);
387 return NS_OK;
390 aValue.Truncate();
391 return NS_OK;
394 NS_IMETHODIMP
395 nsDOMWindowUtils::UpdateLayerTree() {
396 if (RefPtr<PresShell> presShell = GetPresShell()) {
397 // Don't flush throttled animations since it might fire MozAfterPaint event
398 // (in WebRender it constantly does), thus the reftest harness can't take
399 // any snapshot until the throttled animations finished.
400 presShell->FlushPendingNotifications(
401 ChangesToFlush(FlushType::Display, false /* flush animations */));
402 RefPtr<nsViewManager> vm = presShell->GetViewManager();
403 if (nsView* view = vm->GetRootView()) {
404 nsAutoScriptBlocker scriptBlocker;
405 presShell->PaintAndRequestComposite(view,
406 PaintFlags::PaintSyncDecodeImages);
407 presShell->GetWindowRenderer()->WaitOnTransactionProcessed();
410 return NS_OK;
413 NS_IMETHODIMP
414 nsDOMWindowUtils::GetDocumentViewerSize(uint32_t* aDisplayWidth,
415 uint32_t* aDisplayHeight) {
416 PresShell* presShell = GetPresShell();
417 LayoutDeviceIntSize displaySize;
419 if (!presShell || !nsLayoutUtils::GetDocumentViewerSize(
420 presShell->GetPresContext(), displaySize)) {
421 return NS_ERROR_FAILURE;
424 *aDisplayWidth = displaySize.width;
425 *aDisplayHeight = displaySize.height;
427 return NS_OK;
430 NS_IMETHODIMP
431 nsDOMWindowUtils::GetViewportInfo(uint32_t aDisplayWidth,
432 uint32_t aDisplayHeight, double* aDefaultZoom,
433 bool* aAllowZoom, double* aMinZoom,
434 double* aMaxZoom, uint32_t* aWidth,
435 uint32_t* aHeight, bool* aAutoSize) {
436 Document* doc = GetDocument();
437 NS_ENSURE_STATE(doc);
439 nsViewportInfo info =
440 doc->GetViewportInfo(ScreenIntSize(aDisplayWidth, aDisplayHeight));
441 *aDefaultZoom = info.GetDefaultZoom().scale;
442 *aAllowZoom = info.IsZoomAllowed();
443 *aMinZoom = info.GetMinZoom().scale;
444 *aMaxZoom = info.GetMaxZoom().scale;
445 CSSIntSize size = gfx::RoundedToInt(info.GetSize());
446 *aWidth = size.width;
447 *aHeight = size.height;
448 *aAutoSize = info.IsAutoSizeEnabled();
449 return NS_OK;
452 NS_IMETHODIMP
453 nsDOMWindowUtils::GetViewportFitInfo(nsAString& aViewportFit) {
454 Document* doc = GetDocument();
455 NS_ENSURE_STATE(doc);
457 ViewportMetaData metaData = doc->GetViewportMetaData();
458 if (metaData.mViewportFit.EqualsLiteral("contain")) {
459 aViewportFit.AssignLiteral("contain");
460 } else if (metaData.mViewportFit.EqualsLiteral("cover")) {
461 aViewportFit.AssignLiteral("cover");
462 } else {
463 aViewportFit.AssignLiteral("auto");
465 return NS_OK;
468 NS_IMETHODIMP
469 nsDOMWindowUtils::SetMousewheelAutodir(Element* aElement, bool aEnabled,
470 bool aHonourRoot) {
471 aElement->SetProperty(nsGkAtoms::forceMousewheelAutodir,
472 reinterpret_cast<void*>(aEnabled));
473 aElement->SetProperty(nsGkAtoms::forceMousewheelAutodirHonourRoot,
474 reinterpret_cast<void*>(aHonourRoot));
475 return NS_OK;
478 NS_IMETHODIMP
479 nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
480 float aWidthPx, float aHeightPx,
481 Element* aElement,
482 uint32_t aPriority) {
483 PresShell* presShell = GetPresShell();
484 if (!presShell) {
485 return NS_ERROR_FAILURE;
488 if (!aElement) {
489 return NS_ERROR_INVALID_ARG;
492 if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
493 return NS_ERROR_INVALID_ARG;
496 bool hadDisplayPort = false;
497 bool wasPainted = false;
498 nsRect oldDisplayPort;
500 DisplayPortPropertyData* currentData =
501 static_cast<DisplayPortPropertyData*>(
502 aElement->GetProperty(nsGkAtoms::DisplayPort));
503 if (currentData) {
504 if (currentData->mPriority > aPriority) {
505 return NS_OK;
507 hadDisplayPort = true;
508 oldDisplayPort = currentData->mRect;
509 wasPainted = currentData->mPainted;
513 nsRect displayport(nsPresContext::CSSPixelsToAppUnits(aXPx),
514 nsPresContext::CSSPixelsToAppUnits(aYPx),
515 nsPresContext::CSSPixelsToAppUnits(aWidthPx),
516 nsPresContext::CSSPixelsToAppUnits(aHeightPx));
518 aElement->RemoveProperty(nsGkAtoms::MinimalDisplayPort);
519 aElement->SetProperty(
520 nsGkAtoms::DisplayPort,
521 new DisplayPortPropertyData(displayport, aPriority, wasPainted),
522 nsINode::DeleteProperty<DisplayPortPropertyData>);
524 DisplayPortUtils::InvalidateForDisplayPortChange(aElement, hadDisplayPort,
525 oldDisplayPort, displayport);
527 nsIFrame* rootFrame = presShell->GetRootFrame();
528 if (rootFrame) {
529 rootFrame->SchedulePaint();
531 // If we are hiding something that is a display root then send empty paint
532 // transaction in order to release retained layers because it won't get
533 // any more paint requests when it is hidden.
534 if (displayport.IsEmpty() &&
535 rootFrame == nsLayoutUtils::GetDisplayRootFrame(rootFrame)) {
536 nsCOMPtr<nsIWidget> widget = GetWidget();
537 if (widget) {
538 using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
539 nsLayoutUtils::PaintFrame(
540 nullptr, rootFrame, nsRegion(), NS_RGB(255, 255, 255),
541 nsDisplayListBuilderMode::Painting, PaintFrameFlags::WidgetLayers);
546 return NS_OK;
549 NS_IMETHODIMP
550 nsDOMWindowUtils::SetDisplayPortMarginsForElement(
551 float aLeftMargin, float aTopMargin, float aRightMargin,
552 float aBottomMargin, Element* aElement, uint32_t aPriority) {
553 PresShell* presShell = GetPresShell();
554 if (!presShell) {
555 return NS_ERROR_FAILURE;
558 if (!aElement) {
559 return NS_ERROR_INVALID_ARG;
562 if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
563 return NS_ERROR_INVALID_ARG;
566 // Note order change of arguments between our function signature and
567 // ScreenMargin constructor.
568 ScreenMargin displayportMargins(aTopMargin, aRightMargin, aBottomMargin,
569 aLeftMargin);
571 DisplayPortUtils::SetDisplayPortMargins(
572 aElement, presShell,
573 DisplayPortMargins::ForContent(aElement, displayportMargins),
574 DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes, aPriority);
576 return NS_OK;
579 NS_IMETHODIMP
580 nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX, int32_t aY,
581 int32_t aWidth, int32_t aHeight,
582 Element* aElement) {
583 PresShell* presShell = GetPresShell();
584 if (!presShell) {
585 return NS_ERROR_FAILURE;
588 if (!aElement) {
589 return NS_ERROR_INVALID_ARG;
592 if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
593 return NS_ERROR_INVALID_ARG;
596 DisplayPortUtils::SetDisplayPortBase(aElement,
597 nsRect(aX, aY, aWidth, aHeight));
599 return NS_OK;
602 NS_IMETHODIMP
603 nsDOMWindowUtils::GetScrollbarSizes(Element* aElement,
604 uint32_t* aOutVerticalScrollbarWidth,
605 uint32_t* aOutHorizontalScrollbarHeight) {
606 nsIScrollableFrame* scrollFrame =
607 nsLayoutUtils::FindScrollableFrameFor(aElement);
608 if (!scrollFrame) {
609 return NS_ERROR_INVALID_ARG;
612 CSSIntMargin scrollbarSizes =
613 RoundedToInt(CSSMargin::FromAppUnits(scrollFrame->GetActualScrollbarSizes(
614 nsIScrollableFrame::ScrollbarSizesOptions::
615 INCLUDE_VISUAL_VIEWPORT_SCROLLBARS)));
616 *aOutVerticalScrollbarWidth = scrollbarSizes.LeftRight();
617 *aOutHorizontalScrollbarHeight = scrollbarSizes.TopBottom();
619 return NS_OK;
622 NS_IMETHODIMP
623 nsDOMWindowUtils::SetResolutionAndScaleTo(float aResolution) {
624 PresShell* presShell = GetPresShell();
625 if (!presShell) {
626 return NS_ERROR_FAILURE;
629 presShell->SetResolutionAndScaleTo(aResolution, ResolutionChangeOrigin::Test);
631 return NS_OK;
634 NS_IMETHODIMP
635 nsDOMWindowUtils::SetRestoreResolution(float aResolution,
636 uint32_t aDisplayWidth,
637 uint32_t aDisplayHeight) {
638 PresShell* presShell = GetPresShell();
639 if (!presShell) {
640 return NS_ERROR_FAILURE;
643 presShell->SetRestoreResolution(
644 aResolution, LayoutDeviceIntSize(aDisplayWidth, aDisplayHeight));
646 return NS_OK;
649 NS_IMETHODIMP
650 nsDOMWindowUtils::GetResolution(float* aResolution) {
651 PresShell* presShell = GetPresShell();
652 if (!presShell) {
653 return NS_ERROR_FAILURE;
656 *aResolution = presShell->GetResolution();
658 return NS_OK;
661 NS_IMETHODIMP
662 nsDOMWindowUtils::SetIsFirstPaint(bool aIsFirstPaint) {
663 if (PresShell* presShell = GetPresShell()) {
664 presShell->SetIsFirstPaint(aIsFirstPaint);
665 return NS_OK;
667 return NS_ERROR_FAILURE;
670 NS_IMETHODIMP
671 nsDOMWindowUtils::GetIsFirstPaint(bool* aIsFirstPaint) {
672 if (PresShell* presShell = GetPresShell()) {
673 *aIsFirstPaint = presShell->GetIsFirstPaint();
674 return NS_OK;
676 return NS_ERROR_FAILURE;
679 NS_IMETHODIMP
680 nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) {
681 if (PresShell* presShell = GetPresShell()) {
682 *aPresShellId = presShell->GetPresShellId();
683 return NS_OK;
685 return NS_ERROR_FAILURE;
688 NS_IMETHODIMP
689 nsDOMWindowUtils::SendMouseEvent(
690 const nsAString& aType, float aX, float aY, int32_t aButton,
691 int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
692 float aPressure, unsigned short aInputSourceArg,
693 bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized,
694 int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount,
695 bool* aPreventDefault) {
696 return SendMouseEventCommon(
697 aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame,
698 aPressure, aInputSourceArg,
699 aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false,
700 aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true,
701 aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false,
702 aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED);
705 NS_IMETHODIMP
706 nsDOMWindowUtils::SendMouseEventToWindow(
707 const nsAString& aType, float aX, float aY, int32_t aButton,
708 int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
709 float aPressure, unsigned short aInputSourceArg,
710 bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized,
711 int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount) {
712 AUTO_PROFILER_LABEL("nsDOMWindowUtils::SendMouseEventToWindow", OTHER);
714 return SendMouseEventCommon(
715 aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame,
716 aPressure, aInputSourceArg,
717 aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true,
718 nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true,
719 aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false,
720 aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED);
723 NS_IMETHODIMP
724 nsDOMWindowUtils::SendMouseEventCommon(
725 const nsAString& aType, float aX, float aY, int32_t aButton,
726 int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
727 float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId,
728 bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized,
729 bool aIsWidgetEventSynthesized, int32_t aButtons) {
730 RefPtr<PresShell> presShell = GetPresShell();
731 PreventDefaultResult preventDefaultResult;
732 nsresult rv = nsContentUtils::SendMouseEvent(
733 presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers,
734 aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow,
735 &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized);
737 if (aPreventDefault) {
738 *aPreventDefault = preventDefaultResult != PreventDefaultResult::No;
741 return rv;
744 NS_IMETHODIMP
745 nsDOMWindowUtils::IsCORSSafelistedRequestHeader(const nsACString& aName,
746 const nsACString& aValue,
747 bool* aRetVal) {
748 NS_ENSURE_ARG_POINTER(aRetVal);
749 *aRetVal = nsContentUtils::IsCORSSafelistedRequestHeader(aName, aValue);
750 return NS_OK;
753 NS_IMETHODIMP
754 nsDOMWindowUtils::SendWheelEvent(float aX, float aY, double aDeltaX,
755 double aDeltaY, double aDeltaZ,
756 uint32_t aDeltaMode, int32_t aModifiers,
757 int32_t aLineOrPageDeltaX,
758 int32_t aLineOrPageDeltaY, uint32_t aOptions) {
759 // get the widget to send the event to
760 nsPoint offset;
761 nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
762 if (!widget) {
763 return NS_ERROR_NULL_POINTER;
766 WidgetWheelEvent wheelEvent(true, eWheel, widget);
767 wheelEvent.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
768 wheelEvent.mDeltaX = aDeltaX;
769 wheelEvent.mDeltaY = aDeltaY;
770 wheelEvent.mDeltaZ = aDeltaZ;
771 wheelEvent.mDeltaMode = aDeltaMode;
772 wheelEvent.mIsMomentum = (aOptions & WHEEL_EVENT_CAUSED_BY_MOMENTUM) != 0;
773 wheelEvent.mIsNoLineOrPageDelta =
774 (aOptions & WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE) != 0;
775 wheelEvent.mCustomizedByUserPrefs =
776 (aOptions & WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS) != 0;
777 wheelEvent.mLineOrPageDeltaX = aLineOrPageDeltaX;
778 wheelEvent.mLineOrPageDeltaY = aLineOrPageDeltaY;
780 nsPresContext* presContext = GetPresContext();
781 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
783 wheelEvent.mRefPoint =
784 nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
786 if (StaticPrefs::test_events_async_enabled()) {
787 widget->DispatchInputEvent(&wheelEvent);
788 } else {
789 nsEventStatus status = nsEventStatus_eIgnore;
790 nsresult rv = widget->DispatchEvent(&wheelEvent, status);
791 NS_ENSURE_SUCCESS(rv, rv);
794 if (widget->AsyncPanZoomEnabled()) {
795 // Computing overflow deltas is not compatible with APZ, so if APZ is
796 // enabled, we skip testing it.
797 return NS_OK;
800 bool failedX = false;
801 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_ZERO) &&
802 wheelEvent.mOverflowDeltaX != 0) {
803 failedX = true;
805 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_POSITIVE) &&
806 wheelEvent.mOverflowDeltaX <= 0) {
807 failedX = true;
809 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_NEGATIVE) &&
810 wheelEvent.mOverflowDeltaX >= 0) {
811 failedX = true;
813 bool failedY = false;
814 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_ZERO) &&
815 wheelEvent.mOverflowDeltaY != 0) {
816 failedY = true;
818 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_POSITIVE) &&
819 wheelEvent.mOverflowDeltaY <= 0) {
820 failedY = true;
822 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_NEGATIVE) &&
823 wheelEvent.mOverflowDeltaY >= 0) {
824 failedY = true;
827 #ifdef DEBUG
828 if (failedX) {
829 nsPrintfCString debugMsg("SendWheelEvent(): unexpected mOverflowDeltaX: %f",
830 wheelEvent.mOverflowDeltaX);
831 NS_WARNING(debugMsg.get());
833 if (failedY) {
834 nsPrintfCString debugMsg("SendWheelEvent(): unexpected mOverflowDeltaY: %f",
835 wheelEvent.mOverflowDeltaY);
836 NS_WARNING(debugMsg.get());
838 #endif
840 return (!failedX && !failedY) ? NS_OK : NS_ERROR_FAILURE;
843 NS_IMETHODIMP
844 nsDOMWindowUtils::SendTouchEvent(
845 const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers,
846 const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs,
847 const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys,
848 const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces,
849 const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs,
850 const nsTArray<int32_t>& aTwists, int32_t aModifiers,
851 bool aIgnoreRootScrollFrame, bool* aPreventDefault) {
852 return SendTouchEventCommon(aType, aIdentifiers, aXs, aYs, aRxs, aRys,
853 aRotationAngles, aForces, aTiltXs, aTiltYs,
854 aTwists, aModifiers, aIgnoreRootScrollFrame,
855 false, aPreventDefault);
858 NS_IMETHODIMP
859 nsDOMWindowUtils::SendTouchEventToWindow(
860 const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers,
861 const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs,
862 const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys,
863 const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces,
864 const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs,
865 const nsTArray<int32_t>& aTwists, int32_t aModifiers,
866 bool aIgnoreRootScrollFrame, bool* aPreventDefault) {
867 return SendTouchEventCommon(aType, aIdentifiers, aXs, aYs, aRxs, aRys,
868 aRotationAngles, aForces, aTiltXs, aTiltYs,
869 aTwists, aModifiers, aIgnoreRootScrollFrame, true,
870 aPreventDefault);
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,
880 bool aIgnoreRootScrollFrame, bool aToWindow, 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;
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;
899 WidgetTouchEvent event(true, msg, widget);
900 event.mFlags.mIsSynthesizedForTests = true;
901 event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
903 nsPresContext* presContext = GetPresContext();
904 if (!presContext) {
905 return NS_ERROR_FAILURE;
907 uint32_t count = aIdentifiers.Length();
908 if (aXs.Length() != count || aYs.Length() != count ||
909 aRxs.Length() != count || aRys.Length() != count ||
910 aRotationAngles.Length() != count || aForces.Length() != count) {
911 return NS_ERROR_INVALID_ARG;
913 event.mTouches.SetCapacity(count);
914 for (uint32_t i = 0; i < count; ++i) {
915 LayoutDeviceIntPoint pt = nsContentUtils::ToWidgetPoint(
916 CSSPoint(aXs[i], aYs[i]), offset, presContext);
917 LayoutDeviceIntPoint radius = LayoutDeviceIntPoint::FromAppUnitsRounded(
918 CSSPoint::ToAppUnits(CSSPoint(aRxs[i], aRys[i])),
919 presContext->AppUnitsPerDevPixel());
921 RefPtr<Touch> t = new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i],
922 aForces[i], aTiltXs[i], aTiltYs[i], aTwists[i]);
924 event.mTouches.AppendElement(t);
927 nsEventStatus status = nsEventStatus_eIgnore;
928 if (aToWindow) {
929 RefPtr<PresShell> presShell;
930 nsView* view = nsContentUtils::GetViewToDispatchEvent(
931 presContext, getter_AddRefs(presShell));
932 if (!presShell || !view) {
933 return NS_ERROR_FAILURE;
935 *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
936 return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
939 if (StaticPrefs::test_events_async_enabled()) {
940 status = widget->DispatchInputEvent(&event).mContentStatus;
941 } else {
942 nsresult rv = widget->DispatchEvent(&event, status);
943 NS_ENSURE_SUCCESS(rv, rv);
946 if (aPreventDefault) {
947 *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
949 return NS_OK;
952 static_assert(
953 static_cast<uint32_t>(nsIWidget::Modifiers::CAPS_LOCK) ==
954 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CAPS_LOCK),
955 "Need to sync CapsLock value between nsIWidget::Modifiers and "
956 "nsIDOMWindowUtils");
957 static_assert(
958 static_cast<uint32_t>(nsIWidget::Modifiers::NUM_LOCK) ==
959 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_NUM_LOCK),
960 "Need to sync NumLock value between nsIWidget::Modifiers and "
961 "nsIDOMWindowUtils");
962 static_assert(
963 static_cast<uint32_t>(nsIWidget::Modifiers::SHIFT_L) ==
964 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_SHIFT_LEFT),
965 "Need to sync ShiftLeft value between nsIWidget::Modifiers and "
966 "nsIDOMWindowUtils");
967 static_assert(
968 static_cast<uint32_t>(nsIWidget::Modifiers::SHIFT_R) ==
969 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_SHIFT_RIGHT),
970 "Need to sync ShiftRight value between nsIWidget::Modifiers and "
971 "nsIDOMWindowUtils");
972 static_assert(
973 static_cast<uint32_t>(nsIWidget::Modifiers::CTRL_L) ==
974 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CONTROL_LEFT),
975 "Need to sync ControlLeft value between nsIWidget::Modifiers and "
976 "nsIDOMWindowUtils");
977 static_assert(
978 static_cast<uint32_t>(nsIWidget::Modifiers::CTRL_R) ==
979 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CONTROL_RIGHT),
980 "Need to sync ControlRight value between nsIWidget::Modifiers "
981 "and nsIDOMWindowUtils");
982 static_assert(
983 static_cast<uint32_t>(nsIWidget::Modifiers::ALT_L) ==
984 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_LEFT),
985 "Need to sync AltLeft value between nsIWidget::Modifiers and "
986 "nsIDOMWindowUtils");
987 static_assert(
988 static_cast<uint32_t>(nsIWidget::Modifiers::ALT_R) ==
989 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_RIGHT),
990 "Need to sync AltRight value between nsIWidget::Modifiers and "
991 "nsIDOMWindowUtils");
992 static_assert(
993 static_cast<uint32_t>(nsIWidget::Modifiers::COMMAND_L) ==
994 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_COMMAND_LEFT),
995 "Need to sync CommandLeft value between nsIWidget::Modifiers and "
996 "nsIDOMWindowUtils");
997 static_assert(
998 static_cast<uint32_t>(nsIWidget::Modifiers::COMMAND_R) ==
999 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_COMMAND_RIGHT),
1000 "Need to sync CommandRight value between nsIWidget::Modifiers "
1001 "and nsIDOMWindowUtils");
1002 static_assert(
1003 static_cast<uint32_t>(nsIWidget::Modifiers::HELP) ==
1004 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_HELP),
1005 "Need to sync Help value between nsIWidget::Modifiers and "
1006 "nsIDOMWindowUtils");
1007 static_assert(
1008 static_cast<uint32_t>(nsIWidget::Modifiers::ALTGRAPH) ==
1009 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_GRAPH),
1010 "Need to sync AltGraph value between nsIWidget::Modifiers and "
1011 "nsIDOMWindowUtils");
1012 static_assert(
1013 static_cast<uint32_t>(nsIWidget::Modifiers::FUNCTION) ==
1014 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_FUNCTION),
1015 "Need to sync Function value between nsIWidget::Modifiers and "
1016 "nsIDOMWindowUtils");
1017 static_assert(static_cast<uint32_t>(nsIWidget::Modifiers::NUMERIC_KEY_PAD) ==
1018 static_cast<uint32_t>(
1019 nsIDOMWindowUtils::NATIVE_MODIFIER_NUMERIC_KEY_PAD),
1020 "Need to sync NumericKeyPad value between nsIWidget::Modifiers "
1021 "and nsIDOMWindowUtils");
1023 static nsIWidget::Modifiers GetWidgetModifiers(uint32_t aNativeModifiers) {
1024 nsIWidget::Modifiers widgetModifiers = static_cast<nsIWidget::Modifiers>(
1025 aNativeModifiers &
1026 (nsIWidget::Modifiers::CAPS_LOCK | nsIWidget::Modifiers::NUM_LOCK |
1027 nsIWidget::Modifiers::SHIFT_L | nsIWidget::Modifiers::SHIFT_R |
1028 nsIWidget::Modifiers::CTRL_L | nsIWidget::Modifiers::CTRL_R |
1029 nsIWidget::Modifiers::ALT_L | nsIWidget::Modifiers::ALT_R |
1030 nsIWidget::Modifiers::COMMAND_L | nsIWidget::Modifiers::COMMAND_R |
1031 nsIWidget::Modifiers::HELP | nsIWidget::Modifiers::ALTGRAPH |
1032 nsIWidget::Modifiers::FUNCTION | nsIWidget::Modifiers::NUMERIC_KEY_PAD));
1033 NS_ASSERTION(static_cast<uint32_t>(widgetModifiers) == aNativeModifiers,
1034 "Invalid value is specified to the native modifiers");
1035 return widgetModifiers;
1038 NS_IMETHODIMP
1039 nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout,
1040 int32_t aNativeKeyCode,
1041 uint32_t aModifiers,
1042 const nsAString& aCharacters,
1043 const nsAString& aUnmodifiedCharacters,
1044 nsIObserver* aObserver) {
1045 // get the widget to send the event to
1046 nsCOMPtr<nsIWidget> widget = GetWidget();
1047 if (!widget) return NS_ERROR_FAILURE;
1049 NS_DispatchToMainThread(NativeInputRunnable::Create(
1050 NewRunnableMethod<int32_t, int32_t, uint32_t, nsString, nsString,
1051 nsIObserver*>(
1052 "nsIWidget::SynthesizeNativeKeyEvent", widget,
1053 &nsIWidget::SynthesizeNativeKeyEvent, aNativeKeyboardLayout,
1054 aNativeKeyCode, static_cast<uint32_t>(GetWidgetModifiers(aModifiers)),
1055 aCharacters, aUnmodifiedCharacters, aObserver)));
1056 return NS_OK;
1059 NS_IMETHODIMP
1060 nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX, int32_t aScreenY,
1061 uint32_t aNativeMessage, int16_t aButton,
1062 uint32_t aModifierFlags,
1063 Element* aElementOnWidget,
1064 nsIObserver* aObserver) {
1065 // get the widget to send the event to
1066 nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElementOnWidget);
1067 if (!widget) {
1068 return NS_ERROR_FAILURE;
1071 nsIWidget::NativeMouseMessage message;
1072 switch (aNativeMessage) {
1073 case NATIVE_MOUSE_MESSAGE_BUTTON_DOWN:
1074 message = nsIWidget::NativeMouseMessage::ButtonDown;
1075 break;
1076 case NATIVE_MOUSE_MESSAGE_BUTTON_UP:
1077 message = nsIWidget::NativeMouseMessage::ButtonUp;
1078 break;
1079 case NATIVE_MOUSE_MESSAGE_MOVE:
1080 message = nsIWidget::NativeMouseMessage::Move;
1081 break;
1082 case NATIVE_MOUSE_MESSAGE_ENTER_WINDOW:
1083 message = nsIWidget::NativeMouseMessage::EnterWindow;
1084 break;
1085 case NATIVE_MOUSE_MESSAGE_LEAVE_WINDOW:
1086 message = nsIWidget::NativeMouseMessage::LeaveWindow;
1087 break;
1088 default:
1089 return NS_ERROR_INVALID_ARG;
1092 NS_DispatchToMainThread(NativeInputRunnable::Create(
1093 NewRunnableMethod<LayoutDeviceIntPoint, nsIWidget::NativeMouseMessage,
1094 MouseButton, nsIWidget::Modifiers, nsIObserver*>(
1095 "nsIWidget::SynthesizeNativeMouseEvent", widget,
1096 &nsIWidget::SynthesizeNativeMouseEvent,
1097 LayoutDeviceIntPoint(aScreenX, aScreenY), message,
1098 static_cast<MouseButton>(aButton), GetWidgetModifiers(aModifierFlags),
1099 aObserver)));
1100 return NS_OK;
1103 NS_IMETHODIMP
1104 nsDOMWindowUtils::SendNativeMouseScrollEvent(
1105 int32_t aScreenX, int32_t aScreenY, uint32_t aNativeMessage, double aDeltaX,
1106 double aDeltaY, double aDeltaZ, uint32_t aModifierFlags,
1107 uint32_t aAdditionalFlags, Element* aElement, nsIObserver* aObserver) {
1108 // get the widget to send the event to
1109 nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement);
1110 if (!widget) {
1111 return NS_ERROR_FAILURE;
1114 NS_DispatchToMainThread(NativeInputRunnable::Create(
1115 NewRunnableMethod<mozilla::LayoutDeviceIntPoint, uint32_t, double, double,
1116 double, uint32_t, uint32_t, nsIObserver*>(
1117 "nsIWidget::SynthesizeNativeMouseScrollEvent", widget,
1118 &nsIWidget::SynthesizeNativeMouseScrollEvent,
1119 LayoutDeviceIntPoint(aScreenX, aScreenY), aNativeMessage, aDeltaX,
1120 aDeltaY, aDeltaZ, aModifierFlags, aAdditionalFlags, aObserver)));
1121 return NS_OK;
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 nsIObserver* aObserver) {
1130 // FYI: This was designed for automated tests, but currently, this is used by
1131 // DevTools to emulate touch events from mouse events in the responsive
1132 // design mode.
1134 nsCOMPtr<nsIWidget> widget = GetWidget();
1135 if (!widget) {
1136 return NS_ERROR_FAILURE;
1139 if (aPressure < 0 || aPressure > 1 || aOrientation > 359) {
1140 return NS_ERROR_INVALID_ARG;
1143 NS_DispatchToMainThread(NativeInputRunnable::Create(
1144 NewRunnableMethod<uint32_t, nsIWidget::TouchPointerState,
1145 LayoutDeviceIntPoint, double, uint32_t, nsIObserver*>(
1146 "nsIWidget::SynthesizeNativeTouchPoint", widget,
1147 &nsIWidget::SynthesizeNativeTouchPoint, aPointerId,
1148 (nsIWidget::TouchPointerState)aTouchState,
1149 LayoutDeviceIntPoint(aScreenX, aScreenY), aPressure, aOrientation,
1150 aObserver)));
1151 return NS_OK;
1154 NS_IMETHODIMP
1155 nsDOMWindowUtils::SendNativeTouchpadPinch(uint32_t aEventPhase, float aScale,
1156 int32_t aScreenX, int32_t aScreenY,
1157 int32_t aModifierFlags) {
1158 nsCOMPtr<nsIWidget> widget = GetWidget();
1159 if (!widget) {
1160 return NS_ERROR_FAILURE;
1162 NS_DispatchToMainThread(NativeInputRunnable::Create(
1163 NewRunnableMethod<nsIWidget::TouchpadGesturePhase, float,
1164 LayoutDeviceIntPoint, int32_t>(
1165 "nsIWidget::SynthesizeNativeTouchPadPinch", widget,
1166 &nsIWidget::SynthesizeNativeTouchPadPinch,
1167 (nsIWidget::TouchpadGesturePhase)aEventPhase, aScale,
1168 LayoutDeviceIntPoint(aScreenX, aScreenY), aModifierFlags)));
1169 return NS_OK;
1172 NS_IMETHODIMP
1173 nsDOMWindowUtils::SendNativeTouchTap(int32_t aScreenX, int32_t aScreenY,
1174 bool aLongTap, nsIObserver* aObserver) {
1175 nsCOMPtr<nsIWidget> widget = GetWidget();
1176 if (!widget) {
1177 return NS_ERROR_FAILURE;
1180 NS_DispatchToMainThread(NativeInputRunnable::Create(
1181 NewRunnableMethod<LayoutDeviceIntPoint, bool, nsIObserver*>(
1182 "nsIWidget::SynthesizeNativeTouchTap", widget,
1183 &nsIWidget::SynthesizeNativeTouchTap,
1184 LayoutDeviceIntPoint(aScreenX, aScreenY), aLongTap, aObserver)));
1185 return NS_OK;
1188 NS_IMETHODIMP
1189 nsDOMWindowUtils::SendNativePenInput(uint32_t aPointerId,
1190 uint32_t aPointerState, int32_t aScreenX,
1191 int32_t aScreenY, double aPressure,
1192 uint32_t aRotation, int32_t aTiltX,
1193 int32_t aTiltY, int32_t aButton,
1194 nsIObserver* aObserver) {
1195 nsCOMPtr<nsIWidget> widget = GetWidget();
1196 if (!widget) {
1197 return NS_ERROR_FAILURE;
1200 if (aPressure < 0 || aPressure > 1 || aRotation > 359 || aTiltX < -90 ||
1201 aTiltX > 90 || aTiltY < -90 || aTiltY > 90) {
1202 return NS_ERROR_INVALID_ARG;
1205 NS_DispatchToMainThread(NativeInputRunnable::Create(
1206 NewRunnableMethod<uint32_t, nsIWidget::TouchPointerState,
1207 LayoutDeviceIntPoint, double, uint32_t, int32_t,
1208 int32_t, int32_t, nsIObserver*>(
1209 "nsIWidget::SynthesizeNativePenInput", widget,
1210 &nsIWidget::SynthesizeNativePenInput, aPointerId,
1211 (nsIWidget::TouchPointerState)aPointerState,
1212 LayoutDeviceIntPoint(aScreenX, aScreenY), aPressure, aRotation,
1213 aTiltX, aTiltY, aButton, aObserver)));
1214 return NS_OK;
1217 NS_IMETHODIMP
1218 nsDOMWindowUtils::SendNativeTouchpadDoubleTap(int32_t aScreenX,
1219 int32_t aScreenY,
1220 int32_t aModifierFlags) {
1221 nsCOMPtr<nsIWidget> widget = GetWidget();
1222 if (!widget) {
1223 return NS_ERROR_FAILURE;
1226 MOZ_ASSERT(aModifierFlags >= 0);
1227 NS_DispatchToMainThread(NativeInputRunnable::Create(
1228 NewRunnableMethod<LayoutDeviceIntPoint, uint32_t>(
1229 "nsIWidget::SynthesizeNativeTouchpadDoubleTap", widget,
1230 &nsIWidget::SynthesizeNativeTouchpadDoubleTap,
1231 LayoutDeviceIntPoint(aScreenX, aScreenY), aModifierFlags)));
1232 return NS_OK;
1235 NS_IMETHODIMP
1236 nsDOMWindowUtils::SendNativeTouchpadPan(uint32_t aEventPhase, int32_t aScreenX,
1237 int32_t aScreenY, double aDeltaX,
1238 double aDeltaY, int32_t aModifierFlags,
1239 nsIObserver* aObserver) {
1240 nsCOMPtr<nsIWidget> widget = GetWidget();
1241 if (!widget) {
1242 return NS_ERROR_FAILURE;
1245 MOZ_ASSERT(aModifierFlags >= 0);
1246 NS_DispatchToMainThread(NativeInputRunnable::Create(
1247 NewRunnableMethod<nsIWidget::TouchpadGesturePhase, LayoutDeviceIntPoint,
1248 double, double, uint32_t, nsIObserver*>(
1249 "nsIWidget::SynthesizeNativeTouchpadPan", widget,
1250 &nsIWidget::SynthesizeNativeTouchpadPan,
1251 (nsIWidget::TouchpadGesturePhase)aEventPhase,
1252 LayoutDeviceIntPoint(aScreenX, aScreenY), aDeltaX, aDeltaY,
1253 aModifierFlags, aObserver)));
1254 return NS_OK;
1257 NS_IMETHODIMP
1258 nsDOMWindowUtils::SuppressAnimation(bool aSuppress) {
1259 nsIWidget* widget = GetWidget();
1260 if (widget) {
1261 widget->SuppressAnimation(aSuppress);
1263 return NS_OK;
1266 NS_IMETHODIMP
1267 nsDOMWindowUtils::ClearSharedStyleSheetCache() {
1268 SharedStyleSheetCache::Clear();
1269 return NS_OK;
1272 NS_IMETHODIMP
1273 nsDOMWindowUtils::GetParsedStyleSheets(uint32_t* aSheets) {
1274 RefPtr<Document> doc = GetDocument();
1275 if (!doc) {
1276 return NS_ERROR_UNEXPECTED;
1279 *aSheets = doc->CSSLoader()->ParsedSheetCount();
1280 return NS_OK;
1283 NS_IMETHODIMP
1284 nsDOMWindowUtils::ClearNativeTouchSequence(nsIObserver* aObserver) {
1285 nsCOMPtr<nsIWidget> widget = GetWidget();
1286 if (!widget) {
1287 return NS_ERROR_FAILURE;
1290 NS_DispatchToMainThread(
1291 NativeInputRunnable::Create(NewRunnableMethod<nsIObserver*>(
1292 "nsIWidget::ClearNativeTouchSequence", widget,
1293 &nsIWidget::ClearNativeTouchSequence, aObserver)));
1294 return NS_OK;
1297 NS_IMETHODIMP
1298 nsDOMWindowUtils::ActivateNativeMenuItemAt(const nsAString& indexString) {
1299 // get the widget to send the event to
1300 nsCOMPtr<nsIWidget> widget = GetWidget();
1301 if (!widget) return NS_ERROR_FAILURE;
1303 return widget->ActivateNativeMenuItemAt(indexString);
1306 NS_IMETHODIMP
1307 nsDOMWindowUtils::ForceUpdateNativeMenuAt(const nsAString& indexString) {
1308 // get the widget to send the event to
1309 nsCOMPtr<nsIWidget> widget = GetWidget();
1310 if (!widget) return NS_ERROR_FAILURE;
1312 return widget->ForceUpdateNativeMenuAt(indexString);
1315 NS_IMETHODIMP
1316 nsDOMWindowUtils::GetSelectionAsPlaintext(nsAString& aResult) {
1317 // Get the widget to send the event to.
1318 nsCOMPtr<nsIWidget> widget = GetWidget();
1319 if (!widget) {
1320 return NS_ERROR_FAILURE;
1323 return widget->GetSelectionAsPlaintext(aResult);
1326 nsIWidget* nsDOMWindowUtils::GetWidget(nsPoint* aOffset) {
1327 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
1328 if (window) {
1329 nsIDocShell* docShell = window->GetDocShell();
1330 if (docShell) {
1331 return nsContentUtils::GetWidget(docShell->GetPresShell(), aOffset);
1335 return nullptr;
1338 nsIWidget* nsDOMWindowUtils::GetWidgetForElement(Element* aElement) {
1339 if (!aElement) {
1340 return GetWidget();
1342 if (Document* doc = aElement->GetUncomposedDoc()) {
1343 if (PresShell* presShell = doc->GetPresShell()) {
1344 nsIFrame* frame = aElement->GetPrimaryFrame();
1345 if (!frame) {
1346 frame = presShell->GetRootFrame();
1348 if (frame) {
1349 return frame->GetNearestWidget();
1354 return nullptr;
1357 NS_IMETHODIMP
1358 nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener* aListener) {
1359 AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GCCC);
1361 nsJSContext::GarbageCollectNow(JS::GCReason::DOM_UTILS);
1362 nsJSContext::CycleCollectNow(CCReason::API, aListener);
1364 return NS_OK;
1367 NS_IMETHODIMP
1368 nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener* aListener) {
1369 nsJSContext::CycleCollectNow(CCReason::API, aListener);
1370 return NS_OK;
1373 static bool ParseGCReason(const nsACString& aStr, JS::GCReason* aReason,
1374 JS::GCReason aDefault) {
1375 if (aStr.IsEmpty()) {
1376 *aReason = aDefault;
1377 return true;
1379 #define CHECK_REASON(name, _) \
1380 if (aStr.EqualsIgnoreCase(#name)) { \
1381 *aReason = JS::GCReason::name; \
1382 return true; \
1384 GCREASONS(CHECK_REASON);
1385 return false;
1388 NS_IMETHODIMP
1389 nsDOMWindowUtils::RunNextCollectorTimer(const nsACString& aReason) {
1390 JS::GCReason reason;
1391 if (!ParseGCReason(aReason, &reason, JS::GCReason::DOM_WINDOW_UTILS)) {
1392 return NS_ERROR_INVALID_ARG;
1395 nsJSContext::RunNextCollectorTimer(reason);
1397 return NS_OK;
1400 NS_IMETHODIMP
1401 nsDOMWindowUtils::PokeGC(const nsACString& aReason) {
1402 JS::GCReason reason;
1403 if (!ParseGCReason(aReason, &reason, JS::GCReason::DOM_WINDOW_UTILS)) {
1404 return NS_ERROR_INVALID_ARG;
1407 nsJSContext::PokeGC(reason, nullptr);
1409 return NS_OK;
1412 NS_IMETHODIMP
1413 nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType, float aX,
1414 float aY, uint32_t aDirection,
1415 double aDelta, int32_t aModifiers,
1416 uint32_t aClickCount) {
1417 // get the widget to send the event to
1418 nsPoint offset;
1419 nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
1420 if (!widget) return NS_ERROR_FAILURE;
1422 EventMessage msg;
1423 if (aType.EqualsLiteral("MozSwipeGestureMayStart")) {
1424 msg = eSwipeGestureMayStart;
1425 } else if (aType.EqualsLiteral("MozSwipeGestureStart")) {
1426 msg = eSwipeGestureStart;
1427 } else if (aType.EqualsLiteral("MozSwipeGestureUpdate")) {
1428 msg = eSwipeGestureUpdate;
1429 } else if (aType.EqualsLiteral("MozSwipeGestureEnd")) {
1430 msg = eSwipeGestureEnd;
1431 } else if (aType.EqualsLiteral("MozSwipeGesture")) {
1432 msg = eSwipeGesture;
1433 } else if (aType.EqualsLiteral("MozMagnifyGestureStart")) {
1434 msg = eMagnifyGestureStart;
1435 } else if (aType.EqualsLiteral("MozMagnifyGestureUpdate")) {
1436 msg = eMagnifyGestureUpdate;
1437 } else if (aType.EqualsLiteral("MozMagnifyGesture")) {
1438 msg = eMagnifyGesture;
1439 } else if (aType.EqualsLiteral("MozRotateGestureStart")) {
1440 msg = eRotateGestureStart;
1441 } else if (aType.EqualsLiteral("MozRotateGestureUpdate")) {
1442 msg = eRotateGestureUpdate;
1443 } else if (aType.EqualsLiteral("MozRotateGesture")) {
1444 msg = eRotateGesture;
1445 } else if (aType.EqualsLiteral("MozTapGesture")) {
1446 msg = eTapGesture;
1447 } else if (aType.EqualsLiteral("MozPressTapGesture")) {
1448 msg = ePressTapGesture;
1449 } else if (aType.EqualsLiteral("MozEdgeUIStarted")) {
1450 msg = eEdgeUIStarted;
1451 } else if (aType.EqualsLiteral("MozEdgeUICanceled")) {
1452 msg = eEdgeUICanceled;
1453 } else if (aType.EqualsLiteral("MozEdgeUICompleted")) {
1454 msg = eEdgeUICompleted;
1455 } else {
1456 return NS_ERROR_FAILURE;
1459 WidgetSimpleGestureEvent event(true, msg, widget);
1460 event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
1461 event.mDirection = aDirection;
1462 event.mDelta = aDelta;
1463 event.mClickCount = aClickCount;
1465 nsPresContext* presContext = GetPresContext();
1466 if (!presContext) return NS_ERROR_FAILURE;
1468 event.mRefPoint =
1469 nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
1471 nsEventStatus status;
1472 return widget->DispatchEvent(&event, status);
1475 NS_IMETHODIMP
1476 nsDOMWindowUtils::ElementFromPoint(float aX, float aY,
1477 bool aIgnoreRootScrollFrame,
1478 bool aFlushLayout, Element** aReturn) {
1479 nsCOMPtr<Document> doc = GetDocument();
1480 NS_ENSURE_STATE(doc);
1482 RefPtr<Element> el = doc->ElementFromPointHelper(
1483 aX, aY, aIgnoreRootScrollFrame, aFlushLayout, ViewportType::Layout);
1484 el.forget(aReturn);
1485 return NS_OK;
1488 NS_IMETHODIMP
1489 nsDOMWindowUtils::NodesFromRect(float aX, float aY, float aTopSize,
1490 float aRightSize, float aBottomSize,
1491 float aLeftSize, bool aIgnoreRootScrollFrame,
1492 bool aFlushLayout, bool aOnlyVisible,
1493 float aVisibleThreshold,
1494 nsINodeList** aReturn) {
1495 RefPtr<Document> doc = GetDocument();
1496 NS_ENSURE_STATE(doc);
1498 auto list = MakeRefPtr<nsSimpleContentList>(doc);
1500 // The visible threshold was omitted or given a zero value (which makes no
1501 // sense), so give a reasonable default.
1502 if (aVisibleThreshold == 0.0f) {
1503 aVisibleThreshold = 1.0f;
1506 AutoTArray<RefPtr<nsINode>, 8> nodes;
1507 doc->NodesFromRect(aX, aY, aTopSize, aRightSize, aBottomSize, aLeftSize,
1508 aIgnoreRootScrollFrame, aFlushLayout, aOnlyVisible,
1509 aVisibleThreshold, nodes);
1510 list->SetCapacity(nodes.Length());
1511 for (auto& node : nodes) {
1512 list->AppendElement(node->AsContent());
1515 list.forget(aReturn);
1516 return NS_OK;
1519 NS_IMETHODIMP
1520 nsDOMWindowUtils::GetTranslationNodes(nsINode* aRoot,
1521 nsITranslationNodeList** aRetVal) {
1522 NS_ENSURE_ARG_POINTER(aRetVal);
1523 nsCOMPtr<nsIContent> root = do_QueryInterface(aRoot);
1524 NS_ENSURE_STATE(root);
1525 nsCOMPtr<Document> doc = GetDocument();
1526 NS_ENSURE_STATE(doc);
1528 if (root->OwnerDoc() != doc) {
1529 return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
1532 nsTHashSet<nsIContent*> translationNodesHash(500);
1533 RefPtr<nsTranslationNodeList> list = new nsTranslationNodeList;
1535 uint32_t limit = 15000;
1537 // We begin iteration with content->GetNextNode because we want to explictly
1538 // skip the root tag from being a translation node.
1539 nsIContent* content = root;
1540 while ((limit > 0) && (content = content->GetNextNode(root))) {
1541 if (!content->IsHTMLElement()) {
1542 continue;
1545 // Skip elements that usually contain non-translatable text content.
1546 if (content->IsAnyOfHTMLElements(nsGkAtoms::script, nsGkAtoms::iframe,
1547 nsGkAtoms::frameset, nsGkAtoms::frame,
1548 nsGkAtoms::code, nsGkAtoms::noscript,
1549 nsGkAtoms::style)) {
1550 continue;
1553 // An element is a translation node if it contains
1554 // at least one text node that has meaningful data
1555 // for translation
1556 for (nsIContent* child = content->GetFirstChild(); child;
1557 child = child->GetNextSibling()) {
1558 if (child->IsText() && child->GetAsText()->HasTextForTranslation()) {
1559 translationNodesHash.Insert(content);
1561 nsIFrame* frame = content->GetPrimaryFrame();
1562 bool isTranslationRoot = frame && frame->IsBlockFrameOrSubclass();
1563 if (!isTranslationRoot) {
1564 // If an element is not a block element, it still
1565 // can be considered a translation root if the parent
1566 // of this element didn't make into the list of nodes
1567 // to be translated.
1568 bool parentInList = false;
1569 nsIContent* parent = content->GetParent();
1570 if (parent) {
1571 parentInList = translationNodesHash.Contains(parent);
1573 isTranslationRoot = !parentInList;
1576 list->AppendElement(content, isTranslationRoot);
1577 --limit;
1578 break;
1583 *aRetVal = list.forget().take();
1584 return NS_OK;
1587 static already_AddRefed<DataSourceSurface> CanvasToDataSourceSurface(
1588 HTMLCanvasElement* aCanvas) {
1589 MOZ_ASSERT(aCanvas);
1590 SurfaceFromElementResult result = nsLayoutUtils::SurfaceFromElement(aCanvas);
1592 MOZ_ASSERT(result.GetSourceSurface());
1593 return result.GetSourceSurface()->GetDataSurface();
1596 NS_IMETHODIMP
1597 nsDOMWindowUtils::CompareCanvases(nsISupports* aCanvas1, nsISupports* aCanvas2,
1598 uint32_t* aMaxDifference, uint32_t* retVal) {
1599 nsCOMPtr<nsIContent> contentCanvas1 = do_QueryInterface(aCanvas1);
1600 nsCOMPtr<nsIContent> contentCanvas2 = do_QueryInterface(aCanvas2);
1601 auto* canvas1 = HTMLCanvasElement::FromNodeOrNull(contentCanvas1);
1602 auto* canvas2 = HTMLCanvasElement::FromNodeOrNull(contentCanvas2);
1604 if (NS_WARN_IF(!canvas1) || NS_WARN_IF(!canvas2)) {
1605 return NS_ERROR_FAILURE;
1608 RefPtr<DataSourceSurface> img1 = CanvasToDataSourceSurface(canvas1);
1609 RefPtr<DataSourceSurface> img2 = CanvasToDataSourceSurface(canvas2);
1611 if (NS_WARN_IF(!img1) || NS_WARN_IF(!img2) ||
1612 NS_WARN_IF(img1->GetSize() != img2->GetSize())) {
1613 return NS_ERROR_FAILURE;
1616 if (img1->Equals(img2)) {
1617 // They point to the same underlying content.
1618 return NS_OK;
1621 DataSourceSurface::ScopedMap map1(img1, DataSourceSurface::READ);
1622 DataSourceSurface::ScopedMap map2(img2, DataSourceSurface::READ);
1624 if (NS_WARN_IF(!map1.IsMapped()) || NS_WARN_IF(!map2.IsMapped())) {
1625 return NS_ERROR_FAILURE;
1628 int v;
1629 IntSize size = img1->GetSize();
1630 int32_t stride1 = map1.GetStride();
1631 int32_t stride2 = map2.GetStride();
1633 // we can optimize for the common all-pass case
1634 if (stride1 == stride2 && stride1 == size.width * 4) {
1635 v = memcmp(map1.GetData(), map2.GetData(), size.width * size.height * 4);
1636 if (v == 0) {
1637 if (aMaxDifference) *aMaxDifference = 0;
1638 *retVal = 0;
1639 return NS_OK;
1643 uint32_t dc = 0;
1644 uint32_t different = 0;
1646 for (int j = 0; j < size.height; j++) {
1647 unsigned char* p1 = map1.GetData() + j * stride1;
1648 unsigned char* p2 = map2.GetData() + j * stride2;
1649 v = memcmp(p1, p2, size.width * 4);
1651 if (v) {
1652 for (int i = 0; i < size.width; i++) {
1653 if (*(uint32_t*)p1 != *(uint32_t*)p2) {
1654 different++;
1656 dc = std::max((uint32_t)abs(p1[0] - p2[0]), dc);
1657 dc = std::max((uint32_t)abs(p1[1] - p2[1]), dc);
1658 dc = std::max((uint32_t)abs(p1[2] - p2[2]), dc);
1659 dc = std::max((uint32_t)abs(p1[3] - p2[3]), dc);
1662 p1 += 4;
1663 p2 += 4;
1668 if (aMaxDifference) *aMaxDifference = dc;
1670 *retVal = different;
1671 return NS_OK;
1674 NS_IMETHODIMP
1675 nsDOMWindowUtils::GetIsMozAfterPaintPending(bool* aResult) {
1676 NS_ENSURE_ARG_POINTER(aResult);
1677 *aResult = false;
1678 nsPresContext* presContext = GetPresContext();
1679 if (!presContext) return NS_OK;
1680 *aResult = presContext->IsDOMPaintEventPending();
1681 return NS_OK;
1684 NS_IMETHODIMP
1685 nsDOMWindowUtils::GetIsInputTaskManagerSuspended(bool* aResult) {
1686 *aResult = InputTaskManager::Get()->IsSuspended();
1687 return NS_OK;
1690 NS_IMETHODIMP
1691 nsDOMWindowUtils::DisableNonTestMouseEvents(bool aDisable) {
1692 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
1693 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
1694 nsIDocShell* docShell = window->GetDocShell();
1695 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
1696 PresShell* presShell = docShell->GetPresShell();
1697 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
1698 presShell->DisableNonTestMouseEvents(aDisable);
1699 return NS_OK;
1702 NS_IMETHODIMP
1703 nsDOMWindowUtils::SuppressEventHandling(bool aSuppress) {
1704 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
1705 NS_ENSURE_STATE(window);
1707 if (aSuppress) {
1708 window->SuppressEventHandling();
1709 } else {
1710 window->UnsuppressEventHandling();
1713 return NS_OK;
1716 static nsresult getScrollXYAppUnits(const nsWeakPtr& aWindow, bool aFlushLayout,
1717 nsPoint& aScrollPos) {
1718 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(aWindow);
1719 nsCOMPtr<Document> doc = window ? window->GetExtantDoc() : nullptr;
1720 NS_ENSURE_STATE(doc);
1722 if (aFlushLayout) {
1723 doc->FlushPendingNotifications(FlushType::Layout);
1726 if (PresShell* presShell = doc->GetPresShell()) {
1727 nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
1728 if (sf) {
1729 aScrollPos = sf->GetScrollPosition();
1732 return NS_OK;
1735 NS_IMETHODIMP
1736 nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX,
1737 int32_t* aScrollY) {
1738 nsPoint scrollPos(0, 0);
1739 nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos);
1740 NS_ENSURE_SUCCESS(rv, rv);
1741 *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
1742 *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
1744 return NS_OK;
1747 NS_IMETHODIMP
1748 nsDOMWindowUtils::GetScrollXYFloat(bool aFlushLayout, float* aScrollX,
1749 float* aScrollY) {
1750 nsPoint scrollPos(0, 0);
1751 nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos);
1752 NS_ENSURE_SUCCESS(rv, rv);
1753 *aScrollX = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.x);
1754 *aScrollY = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.y);
1756 return NS_OK;
1759 NS_IMETHODIMP
1760 nsDOMWindowUtils::ScrollToVisual(float aOffsetX, float aOffsetY,
1761 int32_t aUpdateType, int32_t aScrollMode) {
1762 nsCOMPtr<Document> doc = GetDocument();
1763 NS_ENSURE_STATE(doc);
1765 nsPresContext* presContext = doc->GetPresContext();
1766 NS_ENSURE_TRUE(presContext, NS_ERROR_NOT_AVAILABLE);
1768 // This should only be called on the root content document.
1769 NS_ENSURE_TRUE(presContext->IsRootContentDocumentCrossProcess(),
1770 NS_ERROR_INVALID_ARG);
1772 FrameMetrics::ScrollOffsetUpdateType updateType;
1773 switch (aUpdateType) {
1774 case UPDATE_TYPE_RESTORE:
1775 updateType = FrameMetrics::eRestore;
1776 break;
1777 case UPDATE_TYPE_MAIN_THREAD:
1778 updateType = FrameMetrics::eMainThread;
1779 break;
1780 default:
1781 return NS_ERROR_INVALID_ARG;
1784 ScrollMode scrollMode;
1785 switch (aScrollMode) {
1786 case SCROLL_MODE_INSTANT:
1787 scrollMode = ScrollMode::Instant;
1788 break;
1789 case SCROLL_MODE_SMOOTH:
1790 scrollMode = ScrollMode::SmoothMsd;
1791 break;
1792 default:
1793 return NS_ERROR_INVALID_ARG;
1796 presContext->PresShell()->ScrollToVisual(
1797 CSSPoint::ToAppUnits(CSSPoint(aOffsetX, aOffsetY)), updateType,
1798 scrollMode);
1800 return NS_OK;
1803 NS_IMETHODIMP
1804 nsDOMWindowUtils::GetVisualViewportOffsetRelativeToLayoutViewport(
1805 float* aOffsetX, float* aOffsetY) {
1806 *aOffsetX = 0;
1807 *aOffsetY = 0;
1809 nsCOMPtr<Document> doc = GetDocument();
1810 NS_ENSURE_STATE(doc);
1812 PresShell* presShell = doc->GetPresShell();
1813 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
1815 nsPoint offset = presShell->GetVisualViewportOffsetRelativeToLayoutViewport();
1816 *aOffsetX = nsPresContext::AppUnitsToFloatCSSPixels(offset.x);
1817 *aOffsetY = nsPresContext::AppUnitsToFloatCSSPixels(offset.y);
1819 return NS_OK;
1822 NS_IMETHODIMP
1823 nsDOMWindowUtils::GetVisualViewportOffset(int32_t* aOffsetX,
1824 int32_t* aOffsetY) {
1825 *aOffsetX = 0;
1826 *aOffsetY = 0;
1828 nsCOMPtr<Document> doc = GetDocument();
1829 NS_ENSURE_STATE(doc);
1831 PresShell* presShell = doc->GetPresShell();
1832 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
1834 nsPoint offset = presShell->GetVisualViewportOffset();
1835 *aOffsetX = nsPresContext::AppUnitsToIntCSSPixels(offset.x);
1836 *aOffsetY = nsPresContext::AppUnitsToIntCSSPixels(offset.y);
1838 return NS_OK;
1841 NS_IMETHODIMP
1842 nsDOMWindowUtils::TransformRectLayoutToVisual(float aX, float aY, float aWidth,
1843 float aHeight,
1844 DOMRect** aResult) {
1845 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
1846 NS_ENSURE_STATE(window);
1848 PresShell* presShell = GetPresShell();
1849 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
1851 CSSRect rect(aX, aY, aWidth, aHeight);
1852 rect = ViewportUtils::DocumentRelativeLayoutToVisual(rect, presShell);
1854 RefPtr<DOMRect> outRect = new DOMRect(window);
1855 outRect->SetRect(rect.x, rect.y, rect.width, rect.height);
1856 outRect.forget(aResult);
1857 return NS_OK;
1860 Result<mozilla::ScreenRect, nsresult> nsDOMWindowUtils::ConvertToScreenRect(
1861 float aX, float aY, float aWidth, float aHeight) {
1862 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
1863 if (!window) {
1864 return Err(NS_ERROR_NOT_AVAILABLE);
1867 PresShell* presShell = GetPresShell();
1868 if (!presShell) {
1869 return Err(NS_ERROR_NOT_AVAILABLE);
1872 nsCOMPtr<nsIWidget> widget = GetWidget();
1873 if (!widget) {
1874 return Err(NS_ERROR_NOT_AVAILABLE);
1877 // Note that if the document is NOT in OOP iframes, i.e. it's in the top level
1878 // content subtree in the same process,
1879 // nsIWidget::WidgetToTopLevelWidgetTransform() doesn't include the desktop
1880 // zoom value, so for documents in the top level content document subtree,
1881 // this ViewportUtils::DocumentRelativeLayoutToVisual call applies the desktop
1882 // zoom value via PresShell::GetResolution() in the function.
1883 CSSRect rect(aX, aY, aWidth, aHeight);
1884 rect = ViewportUtils::DocumentRelativeLayoutToVisual(rect, presShell);
1886 nsPresContext* presContext = presShell->GetPresContext();
1887 MOZ_ASSERT(presContext);
1889 // For OOP iframe documents, we don't have desktop zoom value specifically in
1890 // each iframe documents (i.e. the in-process root presshell's resolution is
1891 // 1.0), instead nsIWidget::WidgetToTopLevelWidgetTransform() includes the
1892 // desktop zoom scale value along with translations by ancestor scroll
1893 // containers, ancestor CSS transforms, etc.
1894 nsRect appUnitsRect = CSSPixel::ToAppUnits(rect);
1895 LayoutDeviceRect devPixelsRect = LayoutDeviceRect::FromAppUnits(
1896 appUnitsRect, presContext->AppUnitsPerDevPixel());
1897 devPixelsRect =
1898 widget->WidgetToTopLevelWidgetTransform().TransformBounds(devPixelsRect) +
1899 widget->TopLevelWidgetToScreenOffset();
1901 return ViewAs<ScreenPixel>(
1902 devPixelsRect, PixelCastJustification::ScreenIsParentLayerForRoot);
1905 NS_IMETHODIMP
1906 nsDOMWindowUtils::ToScreenRectInCSSUnits(float aX, float aY, float aWidth,
1907 float aHeight, DOMRect** aResult) {
1908 ScreenRect rect;
1909 MOZ_TRY_VAR(rect, ConvertToScreenRect(aX, aY, aWidth, aHeight));
1911 nsPresContext* presContext = GetPresContext();
1912 MOZ_ASSERT(presContext);
1914 const auto devRect = ViewAs<LayoutDevicePixel>(
1915 rect, PixelCastJustification::ScreenIsParentLayerForRoot);
1917 // We want to return the screen rect in CSS units of the browser chrome.
1919 // TODO(emilio): It'd be cleaner to convert callers to use plain toScreenRect,
1920 // and perform the screen -> CSS rect in the parent process instead, probably.
1921 const nsRect appUnitsRect = LayoutDeviceRect::ToAppUnits(
1922 devRect,
1923 presContext->DeviceContext()->AppUnitsPerDevPixelInTopLevelChromePage());
1925 RefPtr<DOMRect> outRect = new DOMRect(mWindow);
1926 outRect->SetLayoutRect(appUnitsRect);
1928 outRect.forget(aResult);
1929 return NS_OK;
1932 NS_IMETHODIMP
1933 nsDOMWindowUtils::ToScreenRect(float aX, float aY, float aWidth, float aHeight,
1934 DOMRect** aResult) {
1935 ScreenRect rect;
1936 MOZ_TRY_VAR(rect, ConvertToScreenRect(aX, aY, aWidth, aHeight));
1938 RefPtr<DOMRect> outRect = new DOMRect(mWindow);
1939 outRect->SetRect(rect.x, rect.y, rect.width, rect.height);
1940 outRect.forget(aResult);
1941 return NS_OK;
1944 NS_IMETHODIMP
1945 nsDOMWindowUtils::ConvertFromParentProcessWidgetToLocal(float aX, float aY,
1946 float aWidth,
1947 float aHeight,
1948 DOMRect** aResult) {
1949 if (!XRE_IsContentProcess()) {
1950 return NS_ERROR_NOT_AVAILABLE;
1953 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
1954 if (!window) {
1955 return NS_ERROR_NOT_AVAILABLE;
1958 nsCOMPtr<nsIWidget> widget = GetWidget();
1959 if (!widget) {
1960 return NS_ERROR_NOT_AVAILABLE;
1963 LayoutDeviceRect devPixelsRect = LayoutDeviceRect(aX, aY, aWidth, aHeight);
1965 Maybe<LayoutDeviceToLayoutDeviceMatrix4x4> inverse =
1966 widget->WidgetToTopLevelWidgetTransform().MaybeInverse();
1967 if (inverse) {
1968 Maybe<LayoutDeviceRect> rect =
1969 UntransformBy(*inverse, devPixelsRect, LayoutDeviceRect::MaxIntRect());
1970 if (rect) {
1971 RefPtr<DOMRect> outRect = new DOMRect(mWindow);
1972 outRect->SetRect(rect->x, rect->y, rect->width, rect->height);
1973 outRect.forget(aResult);
1974 return NS_OK;
1978 RefPtr<DOMRect> outRect = new DOMRect(mWindow);
1979 outRect->SetRect(0, 0, 0, 0);
1980 outRect.forget(aResult);
1981 return NS_ERROR_NOT_AVAILABLE;
1984 NS_IMETHODIMP
1985 nsDOMWindowUtils::SetDynamicToolbarMaxHeight(uint32_t aHeightInScreen) {
1986 if (aHeightInScreen > INT32_MAX) {
1987 return NS_ERROR_INVALID_ARG;
1990 RefPtr<nsPresContext> presContext = GetPresContext();
1991 if (!presContext) {
1992 return NS_OK;
1995 MOZ_ASSERT(presContext->IsRootContentDocumentCrossProcess());
1997 presContext->SetDynamicToolbarMaxHeight(ScreenIntCoord(aHeightInScreen));
1999 return NS_OK;
2002 NS_IMETHODIMP
2003 nsDOMWindowUtils::GetScrollbarSize(bool aFlushLayout, int32_t* aWidth,
2004 int32_t* aHeight) {
2005 *aWidth = 0;
2006 *aHeight = 0;
2008 nsCOMPtr<Document> doc = GetDocument();
2009 NS_ENSURE_STATE(doc);
2011 if (aFlushLayout) {
2012 doc->FlushPendingNotifications(FlushType::Layout);
2015 PresShell* presShell = doc->GetPresShell();
2016 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
2018 nsIScrollableFrame* scrollFrame = presShell->GetRootScrollFrameAsScrollable();
2019 NS_ENSURE_TRUE(scrollFrame, NS_OK);
2021 nsMargin sizes = scrollFrame->GetActualScrollbarSizes();
2022 *aWidth = nsPresContext::AppUnitsToIntCSSPixels(sizes.LeftRight());
2023 *aHeight = nsPresContext::AppUnitsToIntCSSPixels(sizes.TopBottom());
2025 return NS_OK;
2028 NS_IMETHODIMP
2029 nsDOMWindowUtils::GetBoundsWithoutFlushing(Element* aElement,
2030 DOMRect** aResult) {
2031 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2032 NS_ENSURE_STATE(window);
2034 NS_ENSURE_ARG_POINTER(aElement);
2036 RefPtr<DOMRect> rect = new DOMRect(window);
2037 nsIFrame* frame = aElement->GetPrimaryFrame();
2039 if (frame) {
2040 nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(
2041 frame, nsLayoutUtils::GetContainingBlockForClientRect(frame),
2042 nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
2043 rect->SetLayoutRect(r);
2046 rect.forget(aResult);
2047 return NS_OK;
2050 NS_IMETHODIMP
2051 nsDOMWindowUtils::NeedsFlush(int32_t aFlushType, bool* aResult) {
2052 MOZ_ASSERT(aResult);
2054 nsCOMPtr<Document> doc = GetDocument();
2055 NS_ENSURE_STATE(doc);
2057 PresShell* presShell = doc->GetPresShell();
2058 NS_ENSURE_STATE(presShell);
2060 FlushType flushType;
2061 switch (aFlushType) {
2062 case FLUSH_STYLE:
2063 flushType = FlushType::Style;
2064 break;
2066 case FLUSH_LAYOUT:
2067 flushType = FlushType::Layout;
2068 break;
2070 case FLUSH_DISPLAY:
2071 flushType = FlushType::Display;
2072 break;
2074 default:
2075 return NS_ERROR_INVALID_ARG;
2078 *aResult = presShell->NeedFlush(flushType);
2079 return NS_OK;
2082 NS_IMETHODIMP
2083 nsDOMWindowUtils::FlushLayoutWithoutThrottledAnimations() {
2084 nsCOMPtr<Document> doc = GetDocument();
2085 if (doc) {
2086 doc->FlushPendingNotifications(
2087 ChangesToFlush(FlushType::Layout, false /* flush animations */));
2090 return NS_OK;
2093 NS_IMETHODIMP
2094 nsDOMWindowUtils::GetRootBounds(DOMRect** aResult) {
2095 Document* doc = GetDocument();
2096 NS_ENSURE_STATE(doc);
2098 nsRect bounds(0, 0, 0, 0);
2099 PresShell* presShell = doc->GetPresShell();
2100 if (presShell) {
2101 nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
2102 if (sf) {
2103 bounds = sf->GetScrollRange();
2104 bounds.SetWidth(bounds.Width() + sf->GetScrollPortRect().Width());
2105 bounds.SetHeight(bounds.Height() + sf->GetScrollPortRect().Height());
2106 } else if (presShell->GetRootFrame()) {
2107 bounds = presShell->GetRootFrame()->GetRect();
2111 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2112 RefPtr<DOMRect> rect = new DOMRect(window);
2113 rect->SetRect(nsPresContext::AppUnitsToFloatCSSPixels(bounds.x),
2114 nsPresContext::AppUnitsToFloatCSSPixels(bounds.y),
2115 nsPresContext::AppUnitsToFloatCSSPixels(bounds.Width()),
2116 nsPresContext::AppUnitsToFloatCSSPixels(bounds.Height()));
2117 rect.forget(aResult);
2118 return NS_OK;
2121 NS_IMETHODIMP
2122 nsDOMWindowUtils::GetIMEIsOpen(bool* aState) {
2123 NS_ENSURE_ARG_POINTER(aState);
2125 nsCOMPtr<nsIWidget> widget = GetWidget();
2126 if (!widget) return NS_ERROR_FAILURE;
2128 // Open state should not be available when IME is not enabled.
2129 InputContext context = widget->GetInputContext();
2130 if (context.mIMEState.mEnabled != IMEEnabled::Enabled) {
2131 return NS_ERROR_NOT_AVAILABLE;
2134 if (context.mIMEState.mOpen == IMEState::OPEN_STATE_NOT_SUPPORTED) {
2135 return NS_ERROR_NOT_IMPLEMENTED;
2137 *aState = (context.mIMEState.mOpen == IMEState::OPEN);
2138 return NS_OK;
2141 NS_IMETHODIMP
2142 nsDOMWindowUtils::GetIMEStatus(uint32_t* aState) {
2143 NS_ENSURE_ARG_POINTER(aState);
2145 nsCOMPtr<nsIWidget> widget = GetWidget();
2146 if (!widget) return NS_ERROR_FAILURE;
2148 InputContext context = widget->GetInputContext();
2149 *aState = static_cast<uint32_t>(context.mIMEState.mEnabled);
2150 return NS_OK;
2153 NS_IMETHODIMP
2154 nsDOMWindowUtils::GetInputContextURI(nsIURI** aURI) {
2155 NS_ENSURE_ARG_POINTER(aURI);
2157 nsCOMPtr<nsIWidget> widget = GetWidget();
2158 if (!widget) {
2159 return NS_ERROR_FAILURE;
2162 nsCOMPtr<nsIURI> documentURI = widget->GetInputContext().mURI;
2163 documentURI.forget(aURI);
2164 return NS_OK;
2167 NS_IMETHODIMP
2168 nsDOMWindowUtils::GetInputContextOrigin(uint32_t* aOrigin) {
2169 NS_ENSURE_ARG_POINTER(aOrigin);
2171 nsCOMPtr<nsIWidget> widget = GetWidget();
2172 if (!widget) {
2173 return NS_ERROR_FAILURE;
2176 InputContext context = widget->GetInputContext();
2177 static_assert(static_cast<uint32_t>(InputContext::Origin::ORIGIN_MAIN) ==
2178 INPUT_CONTEXT_ORIGIN_MAIN);
2179 static_assert(static_cast<uint32_t>(InputContext::Origin::ORIGIN_CONTENT) ==
2180 INPUT_CONTEXT_ORIGIN_CONTENT);
2181 MOZ_ASSERT(context.mOrigin == InputContext::Origin::ORIGIN_MAIN ||
2182 context.mOrigin == InputContext::Origin::ORIGIN_CONTENT);
2183 *aOrigin = static_cast<uint32_t>(context.mOrigin);
2184 return NS_OK;
2187 NS_IMETHODIMP
2188 nsDOMWindowUtils::GetNodeObservedByIMEContentObserver(nsINode** aNode) {
2189 NS_ENSURE_ARG_POINTER(aNode);
2191 IMEContentObserver* observer = IMEStateManager::GetActiveContentObserver();
2192 if (!observer) {
2193 *aNode = nullptr;
2194 return NS_OK;
2196 *aNode = do_AddRef(observer->GetObservingElement()).take();
2197 return NS_OK;
2200 NS_IMETHODIMP
2201 nsDOMWindowUtils::GetCanvasBackgroundColor(nsAString& aColor) {
2202 if (RefPtr<Document> doc = GetDocument()) {
2203 doc->FlushPendingNotifications(FlushType::Frames);
2205 nscolor color = NS_RGB(255, 255, 255);
2206 if (PresShell* presShell = GetPresShell()) {
2207 color = presShell->ComputeCanvasBackground().mViewportColor;
2209 nsStyleUtil::GetSerializedColorValue(color, aColor);
2210 return NS_OK;
2213 NS_IMETHODIMP
2214 nsDOMWindowUtils::GetFocusedInputType(nsAString& aType) {
2215 nsCOMPtr<nsIWidget> widget = GetWidget();
2216 if (!widget) {
2217 return NS_ERROR_FAILURE;
2220 aType = widget->GetInputContext().mHTMLInputType;
2221 return NS_OK;
2224 NS_IMETHODIMP
2225 nsDOMWindowUtils::GetFocusedActionHint(nsAString& aType) {
2226 nsCOMPtr<nsIWidget> widget = GetWidget();
2227 if (!widget) {
2228 return NS_ERROR_FAILURE;
2231 aType = widget->GetInputContext().mActionHint;
2232 return NS_OK;
2235 NS_IMETHODIMP
2236 nsDOMWindowUtils::GetFocusedInputMode(nsAString& aInputMode) {
2237 nsCOMPtr<nsIWidget> widget = GetWidget();
2238 if (!widget) {
2239 return NS_ERROR_FAILURE;
2241 aInputMode = widget->GetInputContext().mHTMLInputMode;
2242 return NS_OK;
2245 NS_IMETHODIMP
2246 nsDOMWindowUtils::GetFocusedAutocapitalize(nsAString& aAutocapitalize) {
2247 nsCOMPtr<nsIWidget> widget = GetWidget();
2248 if (!widget) {
2249 return NS_ERROR_FAILURE;
2251 aAutocapitalize = widget->GetInputContext().mAutocapitalize;
2252 return NS_OK;
2255 NS_IMETHODIMP
2256 nsDOMWindowUtils::GetViewId(Element* aElement, nsViewID* aResult) {
2257 if (aElement && nsLayoutUtils::FindIDFor(aElement, aResult)) {
2258 return NS_OK;
2260 return NS_ERROR_NOT_AVAILABLE;
2263 NS_IMETHODIMP nsDOMWindowUtils::DispatchDOMEventViaPresShellForTesting(
2264 nsINode* aTarget, Event* aEvent, bool* aRetVal) {
2265 NS_ENSURE_STATE(aEvent);
2266 aEvent->SetTrusted(true);
2267 WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
2268 NS_ENSURE_STATE(internalEvent);
2269 // This API is currently used only by EventUtils.js. Thus we should always
2270 // set mIsSynthesizedForTests to true.
2271 internalEvent->mFlags.mIsSynthesizedForTests = true;
2272 nsCOMPtr<nsIContent> content = nsIContent::FromNodeOrNull(aTarget);
2273 NS_ENSURE_STATE(content);
2274 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2275 if (content->OwnerDoc()->GetWindow() != window) {
2276 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
2278 nsCOMPtr<Document> targetDoc = content->GetUncomposedDoc();
2279 NS_ENSURE_STATE(targetDoc);
2280 RefPtr<PresShell> targetPresShell = targetDoc->GetPresShell();
2281 NS_ENSURE_STATE(targetPresShell);
2283 targetDoc->FlushPendingNotifications(FlushType::Layout);
2285 nsEventStatus status = nsEventStatus_eIgnore;
2286 targetPresShell->HandleEventWithTarget(internalEvent, nullptr, content,
2287 &status);
2288 *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
2289 return NS_OK;
2292 static void InitEvent(WidgetGUIEvent& aEvent,
2293 LayoutDeviceIntPoint* aPt = nullptr) {
2294 if (aPt) {
2295 aEvent.mRefPoint = *aPt;
2299 NS_IMETHODIMP
2300 nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType, int64_t aOffset,
2301 uint32_t aLength, int32_t aX,
2302 int32_t aY, uint32_t aAdditionalFlags,
2303 nsIQueryContentEventResult** aResult) {
2304 *aResult = nullptr;
2306 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2307 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
2309 nsIDocShell* docShell = window->GetDocShell();
2310 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
2312 PresShell* presShell = docShell->GetPresShell();
2313 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
2315 nsPresContext* presContext = presShell->GetPresContext();
2316 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
2318 // get the widget to send the event to
2319 nsCOMPtr<nsIWidget> widget = GetWidget();
2320 if (!widget) {
2321 return NS_ERROR_FAILURE;
2324 EventMessage message;
2325 switch (aType) {
2326 case QUERY_SELECTED_TEXT:
2327 message = eQuerySelectedText;
2328 break;
2329 case QUERY_TEXT_CONTENT:
2330 message = eQueryTextContent;
2331 break;
2332 case QUERY_CARET_RECT:
2333 message = eQueryCaretRect;
2334 break;
2335 case QUERY_TEXT_RECT:
2336 message = eQueryTextRect;
2337 break;
2338 case QUERY_EDITOR_RECT:
2339 message = eQueryEditorRect;
2340 break;
2341 case QUERY_CHARACTER_AT_POINT:
2342 message = eQueryCharacterAtPoint;
2343 break;
2344 case QUERY_TEXT_RECT_ARRAY:
2345 message = eQueryTextRectArray;
2346 break;
2347 default:
2348 return NS_ERROR_INVALID_ARG;
2351 SelectionType selectionType = SelectionType::eNormal;
2352 static const uint32_t kSelectionFlags =
2353 QUERY_CONTENT_FLAG_SELECTION_SPELLCHECK |
2354 QUERY_CONTENT_FLAG_SELECTION_IME_RAWINPUT |
2355 QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDRAWTEXT |
2356 QUERY_CONTENT_FLAG_SELECTION_IME_CONVERTEDTEXT |
2357 QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDCONVERTEDTEXT |
2358 QUERY_CONTENT_FLAG_SELECTION_ACCESSIBILITY |
2359 QUERY_CONTENT_FLAG_SELECTION_FIND |
2360 QUERY_CONTENT_FLAG_SELECTION_URLSECONDARY |
2361 QUERY_CONTENT_FLAG_SELECTION_URLSTRIKEOUT;
2362 switch (aAdditionalFlags & kSelectionFlags) {
2363 case QUERY_CONTENT_FLAG_SELECTION_SPELLCHECK:
2364 selectionType = SelectionType::eSpellCheck;
2365 break;
2366 case QUERY_CONTENT_FLAG_SELECTION_IME_RAWINPUT:
2367 selectionType = SelectionType::eIMERawClause;
2368 break;
2369 case QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDRAWTEXT:
2370 selectionType = SelectionType::eIMESelectedRawClause;
2371 break;
2372 case QUERY_CONTENT_FLAG_SELECTION_IME_CONVERTEDTEXT:
2373 selectionType = SelectionType::eIMEConvertedClause;
2374 break;
2375 case QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDCONVERTEDTEXT:
2376 selectionType = SelectionType::eIMESelectedClause;
2377 break;
2378 case QUERY_CONTENT_FLAG_SELECTION_ACCESSIBILITY:
2379 selectionType = SelectionType::eAccessibility;
2380 break;
2381 case QUERY_CONTENT_FLAG_SELECTION_FIND:
2382 selectionType = SelectionType::eFind;
2383 break;
2384 case QUERY_CONTENT_FLAG_SELECTION_URLSECONDARY:
2385 selectionType = SelectionType::eURLSecondary;
2386 break;
2387 case QUERY_CONTENT_FLAG_SELECTION_URLSTRIKEOUT:
2388 selectionType = SelectionType::eURLStrikeout;
2389 break;
2390 case 0:
2391 break;
2392 default:
2393 return NS_ERROR_INVALID_ARG;
2396 if (selectionType != SelectionType::eNormal &&
2397 message != eQuerySelectedText) {
2398 return NS_ERROR_INVALID_ARG;
2401 nsCOMPtr<nsIWidget> targetWidget = widget;
2402 LayoutDeviceIntPoint pt(aX, aY);
2404 WidgetQueryContentEvent::Options options;
2405 options.mUseNativeLineBreak =
2406 !(aAdditionalFlags & QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
2407 options.mRelativeToInsertionPoint =
2408 (aAdditionalFlags &
2409 QUERY_CONTENT_FLAG_OFFSET_RELATIVE_TO_INSERTION_POINT) != 0;
2410 if (options.mRelativeToInsertionPoint) {
2411 switch (message) {
2412 case eQueryTextContent:
2413 case eQueryCaretRect:
2414 case eQueryTextRect:
2415 break;
2416 default:
2417 return NS_ERROR_INVALID_ARG;
2419 } else if (aOffset < 0) {
2420 return NS_ERROR_INVALID_ARG;
2423 if (message == eQueryCharacterAtPoint) {
2424 // Looking for the widget at the point.
2425 nsIFrame* popupFrame = nsLayoutUtils::GetPopupFrameForPoint(
2426 presContext->GetRootPresContext(), widget, pt);
2428 LayoutDeviceIntRect widgetBounds = widget->GetClientBounds();
2429 widgetBounds.MoveTo(0, 0);
2431 // There is no popup frame at the point and the point isn't in our widget,
2432 // we cannot process this request.
2433 NS_ENSURE_TRUE(popupFrame || widgetBounds.Contains(pt), NS_ERROR_FAILURE);
2435 // Fire the event on the widget at the point
2436 if (popupFrame) {
2437 targetWidget = popupFrame->GetNearestWidget();
2441 pt += widget->WidgetToScreenOffset() - targetWidget->WidgetToScreenOffset();
2443 WidgetQueryContentEvent queryEvent(true, message, targetWidget);
2444 InitEvent(queryEvent, &pt);
2446 switch (message) {
2447 case eQueryTextContent:
2448 queryEvent.InitForQueryTextContent(aOffset, aLength, options);
2449 break;
2450 case eQueryCaretRect:
2451 queryEvent.InitForQueryCaretRect(aOffset, options);
2452 break;
2453 case eQueryTextRect:
2454 queryEvent.InitForQueryTextRect(aOffset, aLength, options);
2455 break;
2456 case eQuerySelectedText:
2457 queryEvent.InitForQuerySelectedText(selectionType, options);
2458 break;
2459 case eQueryTextRectArray:
2460 queryEvent.InitForQueryTextRectArray(aOffset, aLength, options);
2461 break;
2462 default:
2463 queryEvent.Init(options);
2464 break;
2467 nsEventStatus status;
2468 nsresult rv = targetWidget->DispatchEvent(&queryEvent, status);
2469 NS_ENSURE_SUCCESS(rv, rv);
2471 auto* result = new nsQueryContentEventResult(std::move(queryEvent));
2472 result->SetEventResult(widget);
2473 NS_ADDREF(*aResult = result);
2474 return NS_OK;
2477 NS_IMETHODIMP
2478 nsDOMWindowUtils::SendSelectionSetEvent(uint32_t aOffset, uint32_t aLength,
2479 uint32_t aAdditionalFlags,
2480 bool* aResult) {
2481 *aResult = false;
2483 // get the widget to send the event to
2484 nsCOMPtr<nsIWidget> widget = GetWidget();
2485 if (!widget) {
2486 return NS_ERROR_FAILURE;
2489 WidgetSelectionEvent selectionEvent(true, eSetSelection, widget);
2490 InitEvent(selectionEvent);
2492 selectionEvent.mOffset = aOffset;
2493 selectionEvent.mLength = aLength;
2494 selectionEvent.mReversed = (aAdditionalFlags & SELECTION_SET_FLAG_REVERSE);
2495 selectionEvent.mUseNativeLineBreak =
2496 !(aAdditionalFlags & SELECTION_SET_FLAG_USE_XP_LINE_BREAK);
2498 nsEventStatus status;
2499 nsresult rv = widget->DispatchEvent(&selectionEvent, status);
2500 NS_ENSURE_SUCCESS(rv, rv);
2502 *aResult = selectionEvent.mSucceeded;
2503 return NS_OK;
2506 NS_IMETHODIMP
2507 nsDOMWindowUtils::SendContentCommandEvent(const nsAString& aType,
2508 nsITransferable* aTransferable,
2509 const nsAString& aString) {
2510 // get the widget to send the event to
2511 nsCOMPtr<nsIWidget> widget = GetWidget();
2512 if (!widget) return NS_ERROR_FAILURE;
2514 EventMessage msg;
2515 if (aType.EqualsLiteral("cut")) {
2516 msg = eContentCommandCut;
2517 } else if (aType.EqualsLiteral("copy")) {
2518 msg = eContentCommandCopy;
2519 } else if (aType.EqualsLiteral("paste")) {
2520 msg = eContentCommandPaste;
2521 } else if (aType.EqualsLiteral("delete")) {
2522 msg = eContentCommandDelete;
2523 } else if (aType.EqualsLiteral("undo")) {
2524 msg = eContentCommandUndo;
2525 } else if (aType.EqualsLiteral("redo")) {
2526 msg = eContentCommandRedo;
2527 } else if (aType.EqualsLiteral("insertText")) {
2528 msg = eContentCommandInsertText;
2529 } else if (aType.EqualsLiteral("pasteTransferable")) {
2530 msg = eContentCommandPasteTransferable;
2531 } else {
2532 return NS_ERROR_FAILURE;
2535 WidgetContentCommandEvent event(true, msg, widget);
2536 if (msg == eContentCommandInsertText) {
2537 event.mString.emplace(aString);
2539 if (msg == eContentCommandPasteTransferable) {
2540 event.mTransferable = aTransferable;
2543 nsEventStatus status;
2544 return widget->DispatchEvent(&event, status);
2547 NS_IMETHODIMP
2548 nsDOMWindowUtils::GetClassName(JS::Handle<JS::Value> aObject, JSContext* aCx,
2549 char** aName) {
2550 // Our argument must be a non-null object.
2551 if (aObject.isPrimitive()) {
2552 return NS_ERROR_XPC_BAD_CONVERT_JS;
2555 *aName = NS_xstrdup(JS::GetClass(aObject.toObjectOrNull())->name);
2556 return NS_OK;
2559 NS_IMETHODIMP
2560 nsDOMWindowUtils::GetVisitedDependentComputedStyle(
2561 Element* aElement, const nsAString& aPseudoElement,
2562 const nsAString& aPropertyName, nsAString& aResult) {
2563 aResult.Truncate();
2565 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2566 NS_ENSURE_STATE(window && aElement);
2567 nsCOMPtr<nsPIDOMWindowInner> innerWindow = window->GetCurrentInnerWindow();
2568 NS_ENSURE_STATE(innerWindow);
2570 nsCOMPtr<nsICSSDeclaration> decl;
2572 ErrorResult rv;
2573 decl = innerWindow->GetComputedStyle(*aElement, aPseudoElement, rv);
2574 ENSURE_SUCCESS(rv, rv.StealNSResult());
2577 nsAutoCString result;
2579 static_cast<nsComputedDOMStyle*>(decl.get())->SetExposeVisitedStyle(true);
2580 decl->GetPropertyValue(NS_ConvertUTF16toUTF8(aPropertyName), result);
2581 static_cast<nsComputedDOMStyle*>(decl.get())->SetExposeVisitedStyle(false);
2583 CopyUTF8toUTF16(result, aResult);
2584 return NS_OK;
2587 NS_IMETHODIMP
2588 nsDOMWindowUtils::EnterModalState() {
2589 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2590 NS_ENSURE_STATE(window);
2592 window->EnterModalState();
2593 return NS_OK;
2596 NS_IMETHODIMP
2597 nsDOMWindowUtils::LeaveModalState() {
2598 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2599 NS_ENSURE_STATE(window);
2601 window->LeaveModalState();
2602 return NS_OK;
2605 NS_IMETHODIMP
2606 nsDOMWindowUtils::IsInModalState(bool* retval) {
2607 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2608 NS_ENSURE_STATE(window);
2610 *retval = nsGlobalWindowOuter::Cast(window)->IsInModalState();
2611 return NS_OK;
2614 NS_IMETHODIMP
2615 nsDOMWindowUtils::SuspendTimeouts() {
2616 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2617 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
2619 nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
2620 NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE);
2622 inner->Suspend();
2624 return NS_OK;
2627 NS_IMETHODIMP
2628 nsDOMWindowUtils::ResumeTimeouts() {
2629 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
2630 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
2632 nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
2633 NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE);
2635 inner->Resume();
2637 return NS_OK;
2640 NS_IMETHODIMP
2641 nsDOMWindowUtils::GetLayerManagerType(nsAString& aType) {
2642 nsCOMPtr<nsIWidget> widget = GetWidget();
2643 if (!widget) return NS_ERROR_FAILURE;
2645 WindowRenderer* renderer = widget->GetWindowRenderer();
2646 if (!renderer) return NS_ERROR_FAILURE;
2648 renderer->GetBackendName(aType);
2650 return NS_OK;
2653 NS_IMETHODIMP
2654 nsDOMWindowUtils::GetLayerManagerRemote(bool* retval) {
2655 nsCOMPtr<nsIWidget> widget = GetWidget();
2656 if (!widget) return NS_ERROR_FAILURE;
2658 WindowRenderer* renderer = widget->GetWindowRenderer();
2659 if (!renderer) return NS_ERROR_FAILURE;
2661 *retval = !!renderer->AsKnowsCompositor();
2662 return NS_OK;
2665 NS_IMETHODIMP
2666 nsDOMWindowUtils::GetIsWebRenderRequested(bool* retval) {
2667 *retval = gfxPlatform::WebRenderPrefEnabled() ||
2668 gfxPlatform::WebRenderEnvvarEnabled();
2669 return NS_OK;
2672 NS_IMETHODIMP
2673 nsDOMWindowUtils::GetCurrentAudioBackend(nsAString& aBackend) {
2674 CubebUtils::GetCurrentBackend(aBackend);
2675 return NS_OK;
2678 NS_IMETHODIMP
2679 nsDOMWindowUtils::GetCurrentMaxAudioChannels(uint32_t* aChannels) {
2680 *aChannels = CubebUtils::MaxNumberOfChannels();
2681 return NS_OK;
2684 NS_IMETHODIMP
2685 nsDOMWindowUtils::GetCurrentPreferredSampleRate(uint32_t* aRate) {
2686 nsCOMPtr<Document> doc = GetDocument();
2687 *aRate = CubebUtils::PreferredSampleRate(
2688 doc ? doc->ShouldResistFingerprinting(RFPTarget::AudioSampleRate)
2689 : nsContentUtils::ShouldResistFingerprinting(
2690 "Fallback", RFPTarget::AudioSampleRate));
2691 return NS_OK;
2694 NS_IMETHODIMP
2695 nsDOMWindowUtils::DefaultDevicesRoundTripLatency(Promise** aOutPromise) {
2696 NS_ENSURE_ARG_POINTER(aOutPromise);
2697 *aOutPromise = nullptr;
2699 nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow);
2700 NS_ENSURE_STATE(outer);
2701 nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
2702 NS_ENSURE_STATE(inner);
2704 ErrorResult err;
2705 RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err);
2706 if (NS_WARN_IF(err.Failed())) {
2707 return err.StealNSResult();
2710 NS_ADDREF(promise.get());
2711 void* p = reinterpret_cast<void*>(promise.get());
2712 NS_DispatchBackgroundTask(
2713 NS_NewRunnableFunction("DefaultDevicesRoundTripLatency", [p]() {
2714 double mean, stddev;
2715 bool success =
2716 CubebUtils::EstimatedRoundTripLatencyDefaultDevices(&mean, &stddev);
2718 NS_DispatchToMainThread(NS_NewRunnableFunction(
2719 "DefaultDevicesRoundTripLatency", [p, success, mean, stddev]() {
2720 Promise* promise = reinterpret_cast<Promise*>(p);
2721 if (!success) {
2722 promise->MaybeReject(NS_ERROR_FAILURE);
2723 NS_RELEASE(promise);
2724 return;
2726 nsTArray<double> a;
2727 a.AppendElement(mean);
2728 a.AppendElement(stddev);
2729 promise->MaybeResolve(a);
2730 NS_RELEASE(promise);
2731 }));
2732 }));
2734 promise.forget(aOutPromise);
2735 return NS_OK;
2738 NS_IMETHODIMP
2739 nsDOMWindowUtils::AudioDevices(uint16_t aSide, nsIArray** aDevices) {
2740 NS_ENSURE_ARG_POINTER(aDevices);
2741 NS_ENSURE_ARG((aSide == AUDIO_INPUT) || (aSide == AUDIO_OUTPUT));
2742 *aDevices = nullptr;
2744 nsresult rv = NS_OK;
2745 nsCOMPtr<nsIMutableArray> devices =
2746 do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
2747 NS_ENSURE_SUCCESS(rv, rv);
2749 RefPtr<CubebDeviceEnumerator> enumerator = Enumerator::GetInstance();
2750 RefPtr<const CubebDeviceEnumerator::AudioDeviceSet> collection;
2751 if (aSide == AUDIO_INPUT) {
2752 collection = enumerator->EnumerateAudioInputDevices();
2753 } else {
2754 collection = enumerator->EnumerateAudioOutputDevices();
2757 for (const auto& device : *collection) {
2758 devices->AppendElement(device);
2761 devices.forget(aDevices);
2763 return NS_OK;
2766 NS_IMETHODIMP
2767 nsDOMWindowUtils::StartFrameTimeRecording(uint32_t* startIndex) {
2768 NS_ENSURE_ARG_POINTER(startIndex);
2770 nsCOMPtr<nsIWidget> widget = GetWidget();
2771 if (!widget) return NS_ERROR_FAILURE;
2773 WindowRenderer* renderer = widget->GetWindowRenderer();
2774 if (!renderer) return NS_ERROR_FAILURE;
2776 const uint32_t kRecordingMinSize = 60 * 10; // 10 seconds @60 fps.
2777 const uint32_t kRecordingMaxSize = 60 * 60 * 60; // One hour
2778 uint32_t bufferSize =
2779 Preferences::GetUint("toolkit.framesRecording.bufferSize", uint32_t(0));
2780 bufferSize = std::min(bufferSize, kRecordingMaxSize);
2781 bufferSize = std::max(bufferSize, kRecordingMinSize);
2782 *startIndex = renderer->StartFrameTimeRecording(bufferSize);
2784 return NS_OK;
2787 NS_IMETHODIMP
2788 nsDOMWindowUtils::StopFrameTimeRecording(uint32_t startIndex,
2789 nsTArray<float>& frameIntervals) {
2790 nsCOMPtr<nsIWidget> widget = GetWidget();
2791 if (!widget) return NS_ERROR_FAILURE;
2793 WindowRenderer* renderer = widget->GetWindowRenderer();
2794 if (!renderer) return NS_ERROR_FAILURE;
2796 renderer->StopFrameTimeRecording(startIndex, frameIntervals);
2798 return NS_OK;
2801 NS_IMETHODIMP
2802 nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds) {
2803 // Before we advance the time, we should trigger any animations that are
2804 // waiting to start. This is because there are many tests that call this
2805 // which expect animations to start immediately. Ideally, we should make
2806 // all these tests do an asynchronous wait on the corresponding animation's
2807 // 'ready' promise before continuing. Then we could remove the special
2808 // handling here and the code path followed when testing would more closely
2809 // match the code path during regular operation. Filed as bug 1112957.
2810 nsPresContext* presContext = GetPresContext();
2811 if (presContext) {
2812 presContext->Document()->Timeline()->TriggerAllPendingAnimationsNow();
2814 RefPtr<nsRefreshDriver> driver = presContext->RefreshDriver();
2815 driver->AdvanceTimeAndRefresh(aMilliseconds);
2817 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
2818 wrbc->SendSetTestSampleTime(driver->MostRecentRefresh());
2822 return NS_OK;
2825 NS_IMETHODIMP
2826 nsDOMWindowUtils::GetLastTransactionId(uint64_t* aLastTransactionId) {
2827 nsCOMPtr<nsIDocShell> docShell = GetDocShell();
2828 if (!docShell) {
2829 return NS_ERROR_UNEXPECTED;
2832 nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
2833 docShell->GetInProcessRootTreeItem(getter_AddRefs(rootTreeItem));
2834 docShell = do_QueryInterface(rootTreeItem);
2835 if (!docShell) {
2836 return NS_ERROR_UNEXPECTED;
2839 nsPresContext* presContext = docShell->GetPresContext();
2840 if (!presContext) {
2841 return NS_ERROR_UNEXPECTED;
2844 nsRefreshDriver* driver = presContext->RefreshDriver();
2845 *aLastTransactionId = uint64_t(driver->LastTransactionId());
2846 return NS_OK;
2849 NS_IMETHODIMP
2850 nsDOMWindowUtils::RestoreNormalRefresh() {
2851 // Kick the compositor out of test mode before the refresh driver, so that
2852 // the refresh driver doesn't send an update that gets ignored by the
2853 // compositor.
2854 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
2855 wrbc->SendLeaveTestMode();
2858 if (nsPresContext* pc = GetPresContext()) {
2859 nsRefreshDriver* driver = pc->RefreshDriver();
2860 driver->RestoreNormalRefresh();
2863 return NS_OK;
2866 NS_IMETHODIMP
2867 nsDOMWindowUtils::GetIsTestControllingRefreshes(bool* aResult) {
2868 nsPresContext* pc = GetPresContext();
2869 *aResult =
2870 pc ? pc->RefreshDriver()->IsTestControllingRefreshesEnabled() : false;
2872 return NS_OK;
2875 NS_IMETHODIMP
2876 nsDOMWindowUtils::GetAsyncPanZoomEnabled(bool* aResult) {
2877 nsIWidget* widget = GetWidget();
2878 if (widget) {
2879 *aResult = widget->AsyncPanZoomEnabled();
2880 } else {
2881 *aResult = gfxPlatform::AsyncPanZoomEnabled();
2883 return NS_OK;
2886 NS_IMETHODIMP
2887 nsDOMWindowUtils::SetAsyncScrollOffset(Element* aElement, float aX, float aY) {
2888 if (!aElement) {
2889 return NS_ERROR_INVALID_ARG;
2891 ScrollableLayerGuid::ViewID viewId;
2892 if (!nsLayoutUtils::FindIDFor(aElement, &viewId)) {
2893 return NS_ERROR_UNEXPECTED;
2895 nsIWidget* widget = GetWidget();
2896 if (!widget) {
2897 return NS_ERROR_FAILURE;
2899 WindowRenderer* renderer = widget->GetWindowRenderer();
2900 if (!renderer) {
2901 return NS_ERROR_FAILURE;
2903 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
2904 WebRenderBridgeChild* wrbc = wr->WrBridge();
2905 if (!wrbc) {
2906 return NS_ERROR_UNEXPECTED;
2908 wrbc->SendSetAsyncScrollOffset(viewId, aX, aY);
2909 return NS_OK;
2911 return NS_ERROR_UNEXPECTED;
2914 NS_IMETHODIMP
2915 nsDOMWindowUtils::SetAsyncZoom(Element* aRootElement, float aValue) {
2916 if (!aRootElement) {
2917 return NS_ERROR_INVALID_ARG;
2919 ScrollableLayerGuid::ViewID viewId;
2920 if (!nsLayoutUtils::FindIDFor(aRootElement, &viewId)) {
2921 return NS_ERROR_UNEXPECTED;
2923 nsIWidget* widget = GetWidget();
2924 if (!widget) {
2925 return NS_ERROR_FAILURE;
2927 WindowRenderer* renderer = widget->GetWindowRenderer();
2928 if (!renderer) {
2929 return NS_ERROR_FAILURE;
2931 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
2932 WebRenderBridgeChild* wrbc = wr->WrBridge();
2933 if (!wrbc) {
2934 return NS_ERROR_UNEXPECTED;
2936 wrbc->SendSetAsyncZoom(viewId, aValue);
2937 return NS_OK;
2939 return NS_ERROR_UNEXPECTED;
2942 NS_IMETHODIMP
2943 nsDOMWindowUtils::FlushApzRepaints(bool* aOutResult) {
2944 nsIWidget* widget = GetWidget();
2945 if (!widget) {
2946 *aOutResult = false;
2947 return NS_OK;
2949 // If APZ is not enabled, this function is a no-op.
2950 if (!widget->AsyncPanZoomEnabled()) {
2951 *aOutResult = false;
2952 return NS_OK;
2954 WindowRenderer* renderer = widget->GetWindowRenderer();
2955 if (!renderer) {
2956 *aOutResult = false;
2957 return NS_OK;
2959 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
2960 WebRenderBridgeChild* wrbc = wr->WrBridge();
2961 if (!wrbc) {
2962 return NS_ERROR_UNEXPECTED;
2964 wrbc->SendFlushApzRepaints();
2965 *aOutResult = true;
2966 return NS_OK;
2968 *aOutResult = false;
2969 return NS_OK;
2972 NS_IMETHODIMP
2973 nsDOMWindowUtils::DisableApzForElement(Element* aElement) {
2974 aElement->SetProperty(nsGkAtoms::apzDisabled, reinterpret_cast<void*>(true));
2975 nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aElement);
2976 if (!sf) {
2977 return NS_OK;
2979 nsIFrame* frame = do_QueryFrame(sf);
2980 if (!frame) {
2981 return NS_OK;
2983 frame->SchedulePaint();
2984 return NS_OK;
2987 static nsTArray<nsIScrollableFrame*> CollectScrollableAncestors(
2988 nsIFrame* aStart) {
2989 nsTArray<nsIScrollableFrame*> result;
2990 nsIFrame* frame = aStart;
2991 while (frame) {
2992 frame = nsLayoutUtils::GetCrossDocParentFrame(frame);
2993 if (!frame) {
2994 break;
2996 nsIScrollableFrame* scrollAncestor =
2997 nsLayoutUtils::GetAsyncScrollableAncestorFrame(frame);
2998 if (!scrollAncestor) {
2999 break;
3001 result.AppendElement(scrollAncestor);
3002 frame = do_QueryFrame(scrollAncestor);
3004 return result;
3007 NS_IMETHODIMP
3008 nsDOMWindowUtils::ZoomToFocusedInput() {
3009 if (!Preferences::GetBool("apz.zoom-to-focused-input.enabled")) {
3010 return NS_OK;
3013 nsIWidget* widget = GetWidget();
3014 if (!widget) {
3015 return NS_OK;
3018 // If APZ is not enabled, this function is a no-op.
3020 // FIXME(emilio): This is not quite true anymore now that we also
3021 // ScrollIntoView() too...
3022 if (!widget->AsyncPanZoomEnabled()) {
3023 return NS_OK;
3026 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3027 if (!fm) {
3028 return NS_OK;
3031 RefPtr<Element> element = fm->GetFocusedElement();
3032 if (!element) {
3033 return NS_OK;
3036 RefPtr<PresShell> presShell =
3037 APZCCallbackHelper::GetRootContentDocumentPresShellForContent(element);
3038 if (!presShell) {
3039 return NS_OK;
3042 // The content may be inside a scrollable subframe inside a non-scrollable
3043 // root content document. In this scenario, we want to ensure that the
3044 // main-thread side knows to scroll the content into view before we get
3045 // the bounding content rect and ask APZ to adjust the visual viewport.
3046 presShell->ScrollContentIntoView(
3047 element, ScrollAxis(WhereToScroll::Nearest, WhenToScroll::IfNotVisible),
3048 ScrollAxis(WhereToScroll::Nearest, WhenToScroll::IfNotVisible),
3049 ScrollFlags::ScrollOverflowHidden);
3051 RefPtr<Document> document = presShell->GetDocument();
3052 if (!document) {
3053 return NS_OK;
3056 uint32_t presShellId;
3057 ScrollableLayerGuid::ViewID viewId;
3058 if (!APZCCallbackHelper::GetOrCreateScrollIdentifiers(
3059 document->GetDocumentElement(), &presShellId, &viewId)) {
3060 return NS_OK;
3063 TouchBehaviorFlags tbf =
3064 layers::TouchActionHelper::GetAllowedTouchBehaviorForFrame(
3065 element->GetPrimaryFrame());
3067 uint32_t flags = layers::DISABLE_ZOOM_OUT | layers::ZOOM_TO_FOCUSED_INPUT;
3068 if (!Preferences::GetBool("formhelper.autozoom") ||
3069 Preferences::GetBool("formhelper.autozoom.force-disable.test-only",
3070 /* aFallback = */ false) ||
3071 !(tbf & AllowedTouchBehavior::ANIMATING_ZOOM)) {
3072 flags |= layers::PAN_INTO_VIEW_ONLY;
3073 } else {
3074 flags |= layers::ONLY_ZOOM_TO_DEFAULT_SCALE;
3077 nsIScrollableFrame* rootScrollFrame =
3078 presShell->GetRootScrollFrameAsScrollable();
3079 if (!rootScrollFrame) {
3080 return NS_OK;
3083 CSSRect bounds;
3084 if (element->IsHTMLElement(nsGkAtoms::input)) {
3085 bounds = nsLayoutUtils::GetBoundingContentRect(element, rootScrollFrame);
3086 } else {
3087 // When focused elment is content editable or <textarea> element,
3088 // focused element will have multi-line content.
3089 nsIFrame* frame = element->GetPrimaryFrame();
3090 if (frame) {
3091 RefPtr<nsCaret> caret = frame->PresShell()->GetCaret();
3092 if (caret && caret->IsVisible()) {
3093 nsRect rect;
3094 if (nsIFrame* frame = caret->GetGeometry(&rect)) {
3095 bounds = nsLayoutUtils::GetBoundingFrameRect(frame, rootScrollFrame);
3099 if (bounds.IsEmpty()) {
3100 // Fallback if no caret frame.
3101 bounds = nsLayoutUtils::GetBoundingContentRect(element, rootScrollFrame);
3105 if (bounds.IsEmpty()) {
3106 // Do not zoom on empty bounds. Bail out.
3107 return NS_OK;
3110 bounds -= CSSPoint::FromAppUnits(rootScrollFrame->GetScrollPosition());
3112 bool waitForRefresh = false;
3113 for (nsIScrollableFrame* scrollAncestor :
3114 CollectScrollableAncestors(element->GetPrimaryFrame())) {
3115 if (scrollAncestor->HasScrollUpdates()) {
3116 waitForRefresh = true;
3117 break;
3120 if (waitForRefresh) {
3121 waitForRefresh = false;
3122 if (nsPresContext* presContext = presShell->GetPresContext()) {
3123 waitForRefresh = true;
3124 presContext->RegisterManagedPostRefreshObserver(
3125 new ManagedPostRefreshObserver(
3126 presContext, [widget = RefPtr<nsIWidget>(widget), presShellId,
3127 viewId, bounds, flags](bool aWasCanceled) {
3128 if (!aWasCanceled) {
3129 widget->ZoomToRect(presShellId, viewId, bounds, flags);
3131 return ManagedPostRefreshObserver::Unregister::Yes;
3132 }));
3135 if (!waitForRefresh) {
3136 widget->ZoomToRect(presShellId, viewId, bounds, flags);
3139 return NS_OK;
3142 NS_IMETHODIMP
3143 nsDOMWindowUtils::ComputeAnimationDistance(Element* aElement,
3144 const nsAString& aProperty,
3145 const nsAString& aValue1,
3146 const nsAString& aValue2,
3147 double* aResult) {
3148 NS_ENSURE_ARG_POINTER(aElement);
3150 nsCSSPropertyID propertyID =
3151 nsCSSProps::LookupProperty(NS_ConvertUTF16toUTF8(aProperty));
3152 if (propertyID == eCSSProperty_UNKNOWN ||
3153 nsCSSProps::IsShorthand(propertyID)) {
3154 return NS_ERROR_ILLEGAL_VALUE;
3157 AnimatedPropertyID property = propertyID == eCSSPropertyExtra_variable
3158 ? AnimatedPropertyID(NS_Atomize(aProperty))
3159 : AnimatedPropertyID(propertyID);
3161 AnimationValue v1 = AnimationValue::FromString(
3162 property, NS_ConvertUTF16toUTF8(aValue1), aElement);
3163 AnimationValue v2 = AnimationValue::FromString(
3164 property, NS_ConvertUTF16toUTF8(aValue2), aElement);
3165 if (v1.IsNull() || v2.IsNull()) {
3166 return NS_ERROR_ILLEGAL_VALUE;
3169 *aResult = v1.ComputeDistance(v2);
3170 return NS_OK;
3173 NS_IMETHODIMP
3174 nsDOMWindowUtils::GetUnanimatedComputedStyle(Element* aElement,
3175 const nsAString& aPseudoElement,
3176 const nsAString& aProperty,
3177 int32_t aFlushType,
3178 nsAString& aResult) {
3179 if (!aElement) {
3180 return NS_ERROR_INVALID_ARG;
3183 nsCSSPropertyID propertyID =
3184 nsCSSProps::LookupProperty(NS_ConvertUTF16toUTF8(aProperty));
3185 if (propertyID == eCSSProperty_UNKNOWN ||
3186 nsCSSProps::IsShorthand(propertyID)) {
3187 return NS_ERROR_INVALID_ARG;
3189 AnimatedPropertyID property =
3190 propertyID == eCSSPropertyExtra_variable
3191 ? AnimatedPropertyID(
3192 NS_Atomize(Substring(aProperty, 2, aProperty.Length() - 2)))
3193 : AnimatedPropertyID(propertyID);
3195 switch (aFlushType) {
3196 case FLUSH_NONE:
3197 break;
3198 case FLUSH_STYLE: {
3199 if (Document* doc = aElement->GetComposedDoc()) {
3200 doc->FlushPendingNotifications(FlushType::Style);
3202 break;
3204 default:
3205 return NS_ERROR_INVALID_ARG;
3208 RefPtr<PresShell> presShell = GetPresShell();
3209 if (!presShell) {
3210 return NS_ERROR_FAILURE;
3213 Maybe<PseudoStyleType> pseudo =
3214 nsCSSPseudoElements::GetPseudoType(aPseudoElement);
3215 if (!pseudo) {
3216 return NS_ERROR_FAILURE;
3218 RefPtr<const ComputedStyle> computedStyle =
3219 nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(aElement, *pseudo);
3220 if (!computedStyle) {
3221 return NS_ERROR_FAILURE;
3224 RefPtr<StyleAnimationValue> value =
3225 Servo_ComputedValues_ExtractAnimationValue(computedStyle, &property)
3226 .Consume();
3227 if (!value) {
3228 return NS_ERROR_FAILURE;
3230 if (!aElement->GetComposedDoc()) {
3231 return NS_ERROR_FAILURE;
3233 nsAutoCString result;
3234 Servo_AnimationValue_Serialize(value, &property,
3235 presShell->StyleSet()->RawData(), &result);
3236 CopyUTF8toUTF16(result, aResult);
3237 return NS_OK;
3240 NS_IMETHODIMP
3241 nsDOMWindowUtils::GetDisplayDPI(float* aDPI) {
3242 nsCOMPtr<nsIWidget> widget = GetWidget();
3243 if (!widget) return NS_ERROR_FAILURE;
3245 *aDPI = widget->GetDPI();
3247 return NS_OK;
3250 NS_IMETHODIMP
3251 nsDOMWindowUtils::CheckAndClearPaintedState(Element* aElement, bool* aResult) {
3252 if (!aElement) {
3253 return NS_ERROR_INVALID_ARG;
3256 nsIFrame* frame = aElement->GetPrimaryFrame();
3258 if (!frame) {
3259 *aResult = false;
3260 return NS_OK;
3263 // Get the outermost frame for the content node, so that we can test
3264 // canvasframe invalidations by observing the documentElement.
3265 for (;;) {
3266 nsIFrame* parentFrame = frame->GetParent();
3267 if (parentFrame && parentFrame->GetContent() == aElement) {
3268 frame = parentFrame;
3269 } else {
3270 break;
3274 while (frame) {
3275 if (!frame->CheckAndClearPaintedState()) {
3276 *aResult = false;
3277 return NS_OK;
3279 frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame);
3281 *aResult = true;
3282 return NS_OK;
3285 NS_IMETHODIMP
3286 nsDOMWindowUtils::CheckAndClearDisplayListState(Element* aElement,
3287 bool* aResult) {
3288 if (!aElement) {
3289 return NS_ERROR_INVALID_ARG;
3292 nsIFrame* frame = aElement->GetPrimaryFrame();
3294 if (!frame) {
3295 *aResult = false;
3296 return NS_OK;
3299 // Get the outermost frame for the content node, so that we can test
3300 // canvasframe invalidations by observing the documentElement.
3301 for (;;) {
3302 nsIFrame* parentFrame = frame->GetParent();
3303 if (parentFrame && parentFrame->GetContent() == aElement) {
3304 frame = parentFrame;
3305 } else {
3306 break;
3310 while (frame) {
3311 if (!frame->CheckAndClearDisplayListState()) {
3312 *aResult = false;
3313 return NS_OK;
3315 frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame);
3317 *aResult = true;
3318 return NS_OK;
3321 NS_IMETHODIMP
3322 nsDOMWindowUtils::IsPartOfOpaqueLayer(Element* aElement, bool* aResult) {
3323 if (!aElement) {
3324 return NS_ERROR_INVALID_ARG;
3327 nsIFrame* frame = aElement->GetPrimaryFrame();
3328 if (!frame) {
3329 return NS_ERROR_FAILURE;
3332 return NS_ERROR_FAILURE;
3335 NS_IMETHODIMP
3336 nsDOMWindowUtils::NumberOfAssignedPaintedLayers(
3337 const nsTArray<RefPtr<Element>>& aElements, uint32_t* aResult) {
3338 return NS_ERROR_FAILURE;
3341 NS_IMETHODIMP
3342 nsDOMWindowUtils::EnableDialogs() {
3343 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3344 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3346 nsGlobalWindowOuter::Cast(window)->EnableDialogs();
3347 return NS_OK;
3350 NS_IMETHODIMP
3351 nsDOMWindowUtils::DisableDialogs() {
3352 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3353 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3355 nsGlobalWindowOuter::Cast(window)->DisableDialogs();
3356 return NS_OK;
3359 NS_IMETHODIMP
3360 nsDOMWindowUtils::AreDialogsEnabled(bool* aResult) {
3361 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3362 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3364 *aResult = nsGlobalWindowOuter::Cast(window)->AreDialogsEnabled();
3365 return NS_OK;
3368 NS_IMETHODIMP
3369 nsDOMWindowUtils::ResetDialogAbuseState() {
3370 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3371 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3373 nsGlobalWindowOuter::Cast(window)
3374 ->GetBrowsingContextGroup()
3375 ->ResetDialogAbuseState();
3376 return NS_OK;
3379 NS_IMETHODIMP
3380 nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx,
3381 int64_t* _retval) {
3382 if (aFile.isPrimitive()) {
3383 *_retval = -1;
3384 return NS_OK;
3387 JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull());
3389 Blob* blob = nullptr;
3390 if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
3391 *_retval = blob->GetFileId();
3392 return NS_OK;
3395 *_retval = -1;
3396 return NS_OK;
3399 NS_IMETHODIMP
3400 nsDOMWindowUtils::GetFilePath(JS::Handle<JS::Value> aFile, JSContext* aCx,
3401 nsAString& _retval) {
3402 if (aFile.isPrimitive()) {
3403 _retval.Truncate();
3404 return NS_OK;
3407 JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull());
3409 File* file = nullptr;
3410 if (NS_SUCCEEDED(UNWRAP_OBJECT(File, &obj, file))) {
3411 nsString filePath;
3412 ErrorResult rv;
3413 file->GetMozFullPathInternal(filePath, rv);
3414 if (NS_WARN_IF(rv.Failed())) {
3415 return rv.StealNSResult();
3418 _retval = filePath;
3419 return NS_OK;
3422 _retval.Truncate();
3423 return NS_OK;
3426 NS_IMETHODIMP
3427 nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId,
3428 int32_t* aRefCnt, int32_t* aDBRefCnt,
3429 bool* aResult) {
3430 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3431 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3433 quota::PrincipalMetadata principalMetadata;
3434 MOZ_TRY_VAR(principalMetadata,
3435 quota::QuotaManager::GetInfoFromWindow(window));
3437 RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
3438 if (mgr) {
3439 nsresult rv = mgr->BlockAndGetFileReferences(
3440 principalMetadata.mIsPrivate ? quota::PERSISTENCE_TYPE_PRIVATE
3441 : quota::PERSISTENCE_TYPE_DEFAULT,
3442 principalMetadata.mOrigin, aDatabaseName, aId, aRefCnt, aDBRefCnt,
3443 aResult);
3445 NS_ENSURE_SUCCESS(rv, rv);
3446 } else {
3447 *aRefCnt = *aDBRefCnt = -1;
3448 *aResult = false;
3451 return NS_OK;
3454 NS_IMETHODIMP
3455 nsDOMWindowUtils::FlushPendingFileDeletions() {
3456 RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
3457 if (mgr) {
3458 nsresult rv = mgr->FlushPendingFileDeletions();
3459 if (NS_WARN_IF(NS_FAILED(rv))) {
3460 return rv;
3464 return NS_OK;
3467 NS_IMETHODIMP
3468 nsDOMWindowUtils::StartPCCountProfiling(JSContext* cx) {
3469 JS::StartPCCountProfiling(cx);
3470 return NS_OK;
3473 NS_IMETHODIMP
3474 nsDOMWindowUtils::StopPCCountProfiling(JSContext* cx) {
3475 JS::StopPCCountProfiling(cx);
3476 return NS_OK;
3479 NS_IMETHODIMP
3480 nsDOMWindowUtils::PurgePCCounts(JSContext* cx) {
3481 JS::PurgePCCounts(cx);
3482 return NS_OK;
3485 NS_IMETHODIMP
3486 nsDOMWindowUtils::GetPCCountScriptCount(JSContext* cx, int32_t* result) {
3487 *result = JS::GetPCCountScriptCount(cx);
3488 return NS_OK;
3491 NS_IMETHODIMP
3492 nsDOMWindowUtils::GetPCCountScriptSummary(int32_t script, JSContext* cx,
3493 nsAString& result) {
3494 JSString* text = JS::GetPCCountScriptSummary(cx, script);
3495 if (!text) return NS_ERROR_FAILURE;
3497 if (!AssignJSString(cx, result, text)) return NS_ERROR_FAILURE;
3499 return NS_OK;
3502 NS_IMETHODIMP
3503 nsDOMWindowUtils::GetPCCountScriptContents(int32_t script, JSContext* cx,
3504 nsAString& result) {
3505 JSString* text = JS::GetPCCountScriptContents(cx, script);
3506 if (!text) return NS_ERROR_FAILURE;
3508 if (!AssignJSString(cx, result, text)) return NS_ERROR_FAILURE;
3510 return NS_OK;
3513 NS_IMETHODIMP
3514 nsDOMWindowUtils::GetPaintingSuppressed(bool* aPaintingSuppressed) {
3515 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3516 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3517 nsIDocShell* docShell = window->GetDocShell();
3518 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
3520 PresShell* presShell = docShell->GetPresShell();
3521 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
3523 *aPaintingSuppressed = presShell->IsPaintingSuppressed();
3524 return NS_OK;
3527 NS_IMETHODIMP
3528 nsDOMWindowUtils::SetVisualViewportSize(float aWidth, float aHeight) {
3529 if (!(aWidth >= 0.0 && aHeight >= 0.0)) {
3530 return NS_ERROR_ILLEGAL_VALUE;
3533 PresShell* presShell = GetPresShell();
3534 if (!presShell) {
3535 return NS_ERROR_FAILURE;
3538 presShell->SetVisualViewportSize(nsPresContext::CSSPixelsToAppUnits(aWidth),
3539 nsPresContext::CSSPixelsToAppUnits(aHeight));
3541 return NS_OK;
3544 nsresult nsDOMWindowUtils::RemoteFrameFullscreenChanged(
3545 Element* aFrameElement) {
3546 nsCOMPtr<Document> doc = GetDocument();
3547 NS_ENSURE_STATE(doc);
3549 doc->RemoteFrameFullscreenChanged(aFrameElement);
3550 return NS_OK;
3553 nsresult nsDOMWindowUtils::RemoteFrameFullscreenReverted() {
3554 nsCOMPtr<Document> doc = GetDocument();
3555 NS_ENSURE_STATE(doc);
3557 doc->RemoteFrameFullscreenReverted();
3558 return NS_OK;
3561 static void PrepareForFullscreenChange(nsIDocShell* aDocShell,
3562 const nsSize& aSize,
3563 nsSize* aOldSize = nullptr) {
3564 if (!aDocShell) {
3565 return;
3567 PresShell* presShell = aDocShell->GetPresShell();
3568 if (!presShell) {
3569 return;
3571 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
3572 rd->SetIsResizeSuppressed();
3573 // Since we are suppressing the resize reflow which would originally
3574 // be triggered by view manager, we need to ensure that the refresh
3575 // driver actually schedules a flush, otherwise it may get stuck.
3576 rd->ScheduleViewManagerFlush();
3578 if (!aSize.IsEmpty()) {
3579 nsCOMPtr<nsIDocumentViewer> viewer;
3580 aDocShell->GetDocViewer(getter_AddRefs(viewer));
3581 if (viewer) {
3582 nsIntRect viewerBounds;
3583 viewer->GetBounds(viewerBounds);
3584 nscoord auPerDev = presShell->GetPresContext()->AppUnitsPerDevPixel();
3585 if (aOldSize) {
3586 *aOldSize = LayoutDeviceIntSize::ToAppUnits(
3587 LayoutDeviceIntSize::FromUnknownSize(viewerBounds.Size()),
3588 auPerDev);
3590 LayoutDeviceIntSize newSize =
3591 LayoutDeviceIntSize::FromAppUnitsRounded(aSize, auPerDev);
3593 viewerBounds.SizeTo(newSize.width, newSize.height);
3594 viewer->SetBounds(viewerBounds);
3599 NS_IMETHODIMP
3600 nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal) {
3601 PROFILER_MARKER_UNTYPED("Enter fullscreen", DOM);
3602 nsCOMPtr<Document> doc = GetDocument();
3603 NS_ENSURE_STATE(doc);
3605 // Notify the pres shell that we are starting fullscreen change, and
3606 // set the window dimensions in advance. Since the resize message
3607 // comes after the fullscreen change call, doing so could avoid an
3608 // extra resize reflow after this point.
3609 nsRect screenRect;
3610 if (nsPresContext* presContext = GetPresContext()) {
3611 presContext->DeviceContext()->GetRect(screenRect);
3613 nsSize oldSize;
3614 PrepareForFullscreenChange(GetDocShell(), screenRect.Size(), &oldSize);
3615 OldWindowSize::Set(mWindow, oldSize);
3617 *aRetVal = Document::HandlePendingFullscreenRequests(doc);
3618 return NS_OK;
3621 nsresult nsDOMWindowUtils::ExitFullscreen(bool aDontRestoreViewSize) {
3622 PROFILER_MARKER_UNTYPED("Exit fullscreen", DOM);
3623 nsCOMPtr<Document> doc = GetDocument();
3624 NS_ENSURE_STATE(doc);
3626 // Although we would not use the old size if we have already exited
3627 // fullscreen, we still want to cleanup in case we haven't.
3628 nsSize oldSize = OldWindowSize::GetAndRemove(mWindow);
3629 if (!doc->GetFullscreenElement()) {
3630 return NS_OK;
3633 // Notify the pres shell that we are starting fullscreen change, and
3634 // set the window dimensions in advance. Since the resize message
3635 // comes after the fullscreen change call, doing so could avoid an
3636 // extra resize reflow after this point.
3637 PrepareForFullscreenChange(GetDocShell(),
3638 aDontRestoreViewSize ? nsSize() : oldSize);
3639 Document::ExitFullscreenInDocTree(doc);
3640 return NS_OK;
3643 NS_IMETHODIMP
3644 nsDOMWindowUtils::SelectAtPoint(float aX, float aY, uint32_t aSelectBehavior,
3645 bool* _retval) {
3646 *_retval = false;
3648 nsSelectionAmount amount;
3649 switch (aSelectBehavior) {
3650 case nsIDOMWindowUtils::SELECT_CHARACTER:
3651 amount = eSelectCharacter;
3652 break;
3653 case nsIDOMWindowUtils::SELECT_CLUSTER:
3654 amount = eSelectCluster;
3655 break;
3656 case nsIDOMWindowUtils::SELECT_WORD:
3657 amount = eSelectWord;
3658 break;
3659 case nsIDOMWindowUtils::SELECT_LINE:
3660 amount = eSelectLine;
3661 break;
3662 case nsIDOMWindowUtils::SELECT_BEGINLINE:
3663 amount = eSelectBeginLine;
3664 break;
3665 case nsIDOMWindowUtils::SELECT_ENDLINE:
3666 amount = eSelectEndLine;
3667 break;
3668 case nsIDOMWindowUtils::SELECT_PARAGRAPH:
3669 amount = eSelectParagraph;
3670 break;
3671 case nsIDOMWindowUtils::SELECT_WORDNOSPACE:
3672 amount = eSelectWordNoSpace;
3673 break;
3674 default:
3675 return NS_ERROR_INVALID_ARG;
3678 PresShell* presShell = GetPresShell();
3679 if (!presShell) {
3680 return NS_ERROR_UNEXPECTED;
3683 // The root frame for this content window
3684 nsIFrame* rootFrame = presShell->GetRootFrame();
3685 if (!rootFrame) {
3686 return NS_ERROR_UNEXPECTED;
3689 // Get the target frame at the client coordinates passed to us
3690 nsPoint offset;
3691 nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
3692 LayoutDeviceIntPoint pt =
3693 nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext());
3694 nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(
3695 widget, pt, RelativeTo{rootFrame});
3696 nsIFrame* targetFrame =
3697 nsLayoutUtils::GetFrameForPoint(RelativeTo{rootFrame}, ptInRoot);
3698 // This can happen if the page hasn't loaded yet or if the point
3699 // is outside the frame.
3700 if (!targetFrame) {
3701 return NS_ERROR_INVALID_ARG;
3704 // Convert point to coordinates relative to the target frame, which is
3705 // what targetFrame's SelectByTypeAtPoint expects.
3706 nsPoint relPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(
3707 widget, pt, RelativeTo{targetFrame});
3709 const RefPtr<nsPresContext> pinnedPresContext{GetPresContext()};
3710 nsresult rv = targetFrame->SelectByTypeAtPoint(
3711 pinnedPresContext, relPoint, amount, amount, nsIFrame::SELECT_ACCUMULATE);
3712 *_retval = !NS_FAILED(rv);
3713 return NS_OK;
3716 static Document::additionalSheetType convertSheetType(uint32_t aSheetType) {
3717 switch (aSheetType) {
3718 case nsDOMWindowUtils::AGENT_SHEET:
3719 return Document::eAgentSheet;
3720 case nsDOMWindowUtils::USER_SHEET:
3721 return Document::eUserSheet;
3722 case nsDOMWindowUtils::AUTHOR_SHEET:
3723 return Document::eAuthorSheet;
3724 default:
3725 NS_ASSERTION(false, "wrong type");
3726 // we must return something although this should never happen
3727 return Document::AdditionalSheetTypeCount;
3731 NS_IMETHODIMP
3732 nsDOMWindowUtils::LoadSheet(nsIURI* aSheetURI, uint32_t aSheetType) {
3733 NS_ENSURE_ARG_POINTER(aSheetURI);
3734 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
3735 aSheetType == AUTHOR_SHEET);
3737 nsCOMPtr<Document> doc = GetDocument();
3738 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
3740 Document::additionalSheetType type = convertSheetType(aSheetType);
3742 return doc->LoadAdditionalStyleSheet(type, aSheetURI);
3745 NS_IMETHODIMP
3746 nsDOMWindowUtils::LoadSheetUsingURIString(const nsACString& aSheetURI,
3747 uint32_t aSheetType) {
3748 nsCOMPtr<nsIURI> uri;
3749 nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI);
3750 NS_ENSURE_SUCCESS(rv, rv);
3752 return LoadSheet(uri, aSheetType);
3755 NS_IMETHODIMP
3756 nsDOMWindowUtils::AddSheet(nsIPreloadedStyleSheet* aSheet,
3757 uint32_t aSheetType) {
3758 NS_ENSURE_ARG_POINTER(aSheet);
3759 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
3760 aSheetType == AUTHOR_SHEET);
3762 nsCOMPtr<Document> doc = GetDocument();
3763 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
3765 StyleSheet* sheet = nullptr;
3766 auto* preloadedSheet = static_cast<PreloadedStyleSheet*>(aSheet);
3767 nsresult rv = preloadedSheet->GetSheet(&sheet);
3768 NS_ENSURE_SUCCESS(rv, rv);
3769 NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
3771 if (sheet->GetAssociatedDocumentOrShadowRoot()) {
3772 return NS_ERROR_INVALID_ARG;
3775 Document::additionalSheetType type = convertSheetType(aSheetType);
3776 return doc->AddAdditionalStyleSheet(type, sheet);
3779 NS_IMETHODIMP
3780 nsDOMWindowUtils::RemoveSheet(nsIURI* aSheetURI, uint32_t aSheetType) {
3781 NS_ENSURE_ARG_POINTER(aSheetURI);
3782 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
3783 aSheetType == AUTHOR_SHEET);
3785 nsCOMPtr<Document> doc = GetDocument();
3786 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
3788 Document::additionalSheetType type = convertSheetType(aSheetType);
3790 doc->RemoveAdditionalStyleSheet(type, aSheetURI);
3791 return NS_OK;
3794 NS_IMETHODIMP
3795 nsDOMWindowUtils::RemoveSheetUsingURIString(const nsACString& aSheetURI,
3796 uint32_t aSheetType) {
3797 nsCOMPtr<nsIURI> uri;
3798 nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI);
3799 NS_ENSURE_SUCCESS(rv, rv);
3801 return RemoveSheet(uri, aSheetType);
3804 NS_IMETHODIMP
3805 nsDOMWindowUtils::GetIsHandlingUserInput(bool* aHandlingUserInput) {
3806 *aHandlingUserInput = UserActivation::IsHandlingUserInput();
3808 return NS_OK;
3811 NS_IMETHODIMP
3812 nsDOMWindowUtils::GetMillisSinceLastUserInput(
3813 double* aMillisSinceLastUserInput) {
3814 TimeStamp lastInput = UserActivation::LatestUserInputStart();
3815 if (lastInput.IsNull()) {
3816 *aMillisSinceLastUserInput = -1.0f;
3817 return NS_OK;
3820 *aMillisSinceLastUserInput = (TimeStamp::Now() - lastInput).ToMilliseconds();
3821 return NS_OK;
3824 NS_IMETHODIMP
3825 nsDOMWindowUtils::AllowScriptsToClose() {
3826 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3827 NS_ENSURE_STATE(window);
3828 nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose();
3829 return NS_OK;
3832 NS_IMETHODIMP
3833 nsDOMWindowUtils::GetIsParentWindowMainWidgetVisible(bool* aIsVisible) {
3834 if (!XRE_IsParentProcess()) {
3835 MOZ_CRASH(
3836 "IsParentWindowMainWidgetVisible is only available in the parent "
3837 "process");
3840 // this should reflect the "is parent window visible" logic in
3841 // nsWindowWatcher::OpenWindowInternal()
3842 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3843 NS_ENSURE_STATE(window);
3845 nsCOMPtr<nsIWidget> parentWidget;
3846 nsIDocShell* docShell = window->GetDocShell();
3847 if (docShell) {
3848 nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
3849 docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
3850 nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(parentTreeOwner));
3851 if (parentWindow) {
3852 parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
3855 if (!parentWidget) {
3856 return NS_ERROR_NOT_AVAILABLE;
3859 *aIsVisible = parentWidget->IsVisible();
3860 return NS_OK;
3863 NS_IMETHODIMP
3864 nsDOMWindowUtils::IsNodeDisabledForEvents(nsINode* aNode, bool* aRetVal) {
3865 *aRetVal = false;
3866 nsINode* node = aNode;
3867 while (node) {
3868 if (node->IsHTMLFormControlElement()) {
3869 nsGenericHTMLElement* element = nsGenericHTMLElement::FromNode(node);
3870 WidgetEvent event(true, eVoidEvent);
3871 if (element && element->IsDisabledForEvents(&event)) {
3872 *aRetVal = true;
3873 break;
3876 node = node->GetParentNode();
3879 return NS_OK;
3882 NS_IMETHODIMP
3883 nsDOMWindowUtils::DispatchEventToChromeOnly(EventTarget* aTarget, Event* aEvent,
3884 bool* aRetVal) {
3885 *aRetVal = false;
3886 NS_ENSURE_STATE(aTarget && aEvent);
3887 aEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3888 *aRetVal =
3889 aTarget->DispatchEvent(*aEvent, CallerType::System, IgnoreErrors());
3890 return NS_OK;
3893 static Result<nsIFrame*, nsresult> GetTargetFrame(
3894 const Element* aElement, const nsAString& aPseudoElement) {
3895 nsIFrame* frame = aElement->GetPrimaryFrame();
3896 if (!aPseudoElement.IsEmpty()) {
3897 if (aPseudoElement.EqualsLiteral("::before")) {
3898 frame = nsLayoutUtils::GetBeforeFrame(aElement);
3899 } else if (aPseudoElement.EqualsLiteral("::after")) {
3900 frame = nsLayoutUtils::GetAfterFrame(aElement);
3901 } else {
3902 return Err(NS_ERROR_INVALID_ARG);
3905 return frame;
3908 static OMTAValue GetOMTAValue(nsIFrame* aFrame, DisplayItemType aDisplayItemKey,
3909 WebRenderBridgeChild* aWebRenderBridgeChild) {
3910 OMTAValue value = mozilla::null_t();
3912 if (aWebRenderBridgeChild) {
3913 RefPtr<WebRenderAnimationData> animationData =
3914 GetWebRenderUserData<WebRenderAnimationData>(aFrame,
3915 (uint32_t)aDisplayItemKey);
3916 if (animationData) {
3917 aWebRenderBridgeChild->SendGetAnimationValue(
3918 animationData->GetAnimationInfo().GetCompositorAnimationsId(),
3919 &value);
3922 return value;
3925 NS_IMETHODIMP
3926 nsDOMWindowUtils::GetOMTAStyle(Element* aElement, const nsAString& aProperty,
3927 const nsAString& aPseudoElement,
3928 nsAString& aResult) {
3929 if (!aElement) {
3930 return NS_ERROR_INVALID_ARG;
3933 auto frameOrError = GetTargetFrame(aElement, aPseudoElement);
3934 if (frameOrError.isErr()) {
3935 return frameOrError.unwrapErr();
3937 nsIFrame* frame = frameOrError.unwrap();
3939 RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
3940 if (frame && nsLayoutUtils::AreAsyncAnimationsEnabled()) {
3941 if (aProperty.EqualsLiteral("opacity")) {
3942 OMTAValue value = GetOMTAValue(frame, DisplayItemType::TYPE_OPACITY,
3943 GetWebRenderBridge());
3944 if (value.type() == OMTAValue::Tfloat) {
3945 cssValue = new nsROCSSPrimitiveValue;
3946 cssValue->SetNumber(value.get_float());
3948 } else if (aProperty.EqualsLiteral("transform") ||
3949 aProperty.EqualsLiteral("translate") ||
3950 aProperty.EqualsLiteral("rotate") ||
3951 aProperty.EqualsLiteral("scale") ||
3952 aProperty.EqualsLiteral("offset-path") ||
3953 aProperty.EqualsLiteral("offset-distance") ||
3954 aProperty.EqualsLiteral("offset-rotate") ||
3955 aProperty.EqualsLiteral("offset-anchor") ||
3956 aProperty.EqualsLiteral("offset-position")) {
3957 OMTAValue value = GetOMTAValue(frame, DisplayItemType::TYPE_TRANSFORM,
3958 GetWebRenderBridge());
3959 if (value.type() == OMTAValue::TMatrix4x4) {
3960 cssValue = nsComputedDOMStyle::MatrixToCSSValue(value.get_Matrix4x4());
3962 } else if (aProperty.EqualsLiteral("background-color")) {
3963 OMTAValue value = GetOMTAValue(
3964 frame, DisplayItemType::TYPE_BACKGROUND_COLOR, GetWebRenderBridge());
3965 if (value.type() == OMTAValue::Tnscolor) {
3966 nsStyleUtil::GetSerializedColorValue(value.get_nscolor(), aResult);
3967 return NS_OK;
3972 if (cssValue) {
3973 cssValue->GetCssText(aResult);
3974 return NS_OK;
3976 aResult.Truncate();
3977 return NS_OK;
3980 namespace {
3982 class HandlingUserInputHelper final : public nsIJSRAIIHelper {
3983 public:
3984 explicit HandlingUserInputHelper(bool aHandlingUserInput);
3986 NS_DECL_ISUPPORTS
3987 NS_DECL_NSIJSRAIIHELPER
3989 private:
3990 ~HandlingUserInputHelper();
3992 bool mHandlingUserInput;
3993 bool mDestructCalled = false;
3996 NS_IMPL_ISUPPORTS(HandlingUserInputHelper, nsIJSRAIIHelper)
3998 HandlingUserInputHelper::HandlingUserInputHelper(bool aHandlingUserInput)
3999 : mHandlingUserInput(aHandlingUserInput) {
4000 if (aHandlingUserInput) {
4001 UserActivation::StartHandlingUserInput(eVoidEvent);
4005 HandlingUserInputHelper::~HandlingUserInputHelper() {
4006 // We assert, but just in case, make sure we notify the ESM.
4007 MOZ_ASSERT(mDestructCalled);
4008 if (!mDestructCalled) {
4009 Destruct();
4013 NS_IMETHODIMP
4014 HandlingUserInputHelper::Destruct() {
4015 if (NS_WARN_IF(mDestructCalled)) {
4016 return NS_ERROR_FAILURE;
4019 mDestructCalled = true;
4020 if (mHandlingUserInput) {
4021 UserActivation::StopHandlingUserInput(eVoidEvent);
4024 return NS_OK;
4027 } // unnamed namespace
4029 NS_IMETHODIMP
4030 nsDOMWindowUtils::SetHandlingUserInput(bool aHandlingUserInput,
4031 nsIJSRAIIHelper** aHelper) {
4032 if (aHandlingUserInput) {
4033 if (Document* doc = GetDocument()) {
4034 doc->NotifyUserGestureActivation();
4037 auto helper = MakeRefPtr<HandlingUserInputHelper>(aHandlingUserInput);
4038 helper.forget(aHelper);
4039 return NS_OK;
4042 NS_IMETHODIMP
4043 nsDOMWindowUtils::IsKeyboardEventUserActivity(Event* aEvent, bool* aResult) {
4044 NS_ENSURE_STATE(aEvent);
4045 if (!aEvent->AsKeyboardEvent()) {
4046 return NS_ERROR_INVALID_ARG;
4049 WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
4050 NS_ENSURE_STATE(internalEvent);
4051 *aResult = EventStateManager::IsKeyboardEventUserActivity(internalEvent);
4052 return NS_OK;
4055 NS_IMETHODIMP
4056 nsDOMWindowUtils::GetContentAPZTestData(
4057 JSContext* aContext, JS::MutableHandle<JS::Value> aOutContentTestData) {
4058 if (nsIWidget* widget = GetWidget()) {
4059 WindowRenderer* renderer = widget->GetWindowRenderer();
4060 if (!renderer) {
4061 return NS_OK;
4063 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
4064 if (!wr->GetAPZTestData().ToJS(aOutContentTestData, aContext)) {
4065 return NS_ERROR_FAILURE;
4070 return NS_OK;
4073 NS_IMETHODIMP
4074 nsDOMWindowUtils::GetCompositorAPZTestData(
4075 JSContext* aContext, JS::MutableHandle<JS::Value> aOutCompositorTestData) {
4076 if (nsIWidget* widget = GetWidget()) {
4077 WindowRenderer* renderer = widget->GetWindowRenderer();
4078 if (!renderer) {
4079 return NS_OK;
4081 APZTestData compositorSideData;
4082 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
4083 if (!wr->WrBridge()) {
4084 return NS_ERROR_UNEXPECTED;
4086 if (!wr->WrBridge()->SendGetAPZTestData(&compositorSideData)) {
4087 return NS_ERROR_FAILURE;
4090 if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) {
4091 return NS_ERROR_FAILURE;
4095 return NS_OK;
4098 NS_IMETHODIMP
4099 nsDOMWindowUtils::PostRestyleSelfEvent(Element* aElement) {
4100 if (!aElement) {
4101 return NS_ERROR_INVALID_ARG;
4104 nsLayoutUtils::PostRestyleEvent(aElement, RestyleHint::RESTYLE_SELF,
4105 nsChangeHint(0));
4106 return NS_OK;
4109 NS_IMETHODIMP
4110 nsDOMWindowUtils::SetChromeMargin(int32_t aTop, int32_t aRight, int32_t aBottom,
4111 int32_t aLeft) {
4112 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
4113 if (window) {
4114 nsCOMPtr<nsIBaseWindow> baseWindow =
4115 do_QueryInterface(window->GetDocShell());
4116 if (baseWindow) {
4117 nsCOMPtr<nsIWidget> widget;
4118 baseWindow->GetMainWidget(getter_AddRefs(widget));
4119 if (widget) {
4120 LayoutDeviceIntMargin margins(aTop, aRight, aBottom, aLeft);
4121 return widget->SetNonClientMargins(margins);
4126 return NS_OK;
4129 NS_IMETHODIMP
4130 nsDOMWindowUtils::SetResizeMargin(int32_t aResizeMargin) {
4131 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
4132 if (window) {
4133 nsCOMPtr<nsIBaseWindow> baseWindow =
4134 do_QueryInterface(window->GetDocShell());
4135 if (baseWindow) {
4136 nsCOMPtr<nsIWidget> widget;
4137 baseWindow->GetMainWidget(getter_AddRefs(widget));
4138 if (widget) {
4139 CSSToLayoutDeviceScale scaleFactor = widget->GetDefaultScale();
4140 widget->SetResizeMargin(
4141 (CSSCoord(float(aResizeMargin)) * scaleFactor).Rounded());
4146 return NS_OK;
4149 NS_IMETHODIMP
4150 nsDOMWindowUtils::GetFrameUniformityTestData(
4151 JSContext* aContext, JS::MutableHandle<JS::Value> aOutFrameUniformity) {
4152 nsIWidget* widget = GetWidget();
4153 if (!widget) {
4154 return NS_ERROR_NOT_AVAILABLE;
4157 WindowRenderer* renderer = widget->GetWindowRenderer();
4158 if (!renderer) {
4159 return NS_ERROR_NOT_AVAILABLE;
4162 FrameUniformityData outData;
4163 renderer->GetFrameUniformity(&outData);
4164 outData.ToJS(aOutFrameUniformity, aContext);
4165 return NS_OK;
4168 NS_IMETHODIMP
4169 nsDOMWindowUtils::XpconnectArgument(nsISupports* aObj) {
4170 // Do nothing.
4171 return NS_OK;
4174 NS_IMETHODIMP
4175 nsDOMWindowUtils::AskPermission(nsIContentPermissionRequest* aRequest) {
4176 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
4177 return nsContentPermissionUtils::AskPermission(
4178 aRequest, window->GetCurrentInnerWindow());
4181 NS_IMETHODIMP
4182 nsDOMWindowUtils::GetRestyleGeneration(uint64_t* aResult) {
4183 nsPresContext* presContext = GetPresContext();
4184 if (!presContext) {
4185 return NS_ERROR_NOT_AVAILABLE;
4188 *aResult = presContext->GetRestyleGeneration();
4189 return NS_OK;
4192 NS_IMETHODIMP
4193 nsDOMWindowUtils::GetFramesConstructed(uint64_t* aResult) {
4194 nsPresContext* presContext = GetPresContext();
4195 if (!presContext) {
4196 return NS_ERROR_NOT_AVAILABLE;
4199 *aResult = presContext->FramesConstructedCount();
4200 return NS_OK;
4203 NS_IMETHODIMP
4204 nsDOMWindowUtils::GetFramesReflowed(uint64_t* aResult) {
4205 nsPresContext* presContext = GetPresContext();
4206 if (!presContext) {
4207 return NS_ERROR_NOT_AVAILABLE;
4210 *aResult = presContext->FramesReflowedCount();
4211 return NS_OK;
4214 NS_IMETHODIMP
4215 nsDOMWindowUtils::GetAnimationTriggeredRestyles(uint64_t* aResult) {
4216 nsPresContext* presContext = GetPresContext();
4217 if (!presContext) {
4218 return NS_ERROR_NOT_AVAILABLE;
4221 *aResult = presContext->AnimationTriggeredRestylesCount();
4222 return NS_OK;
4225 NS_IMETHODIMP
4226 nsDOMWindowUtils::GetRefreshDriverHasPendingTick(bool* aResult) {
4227 nsPresContext* presContext = GetPresContext();
4228 if (!presContext) {
4229 return NS_ERROR_NOT_AVAILABLE;
4232 *aResult = presContext->RefreshDriver()->HasPendingTick();
4233 return NS_OK;
4236 NS_IMETHODIMP
4237 nsDOMWindowUtils::EnterChaosMode() {
4238 ChaosMode::enterChaosMode();
4239 return NS_OK;
4242 NS_IMETHODIMP
4243 nsDOMWindowUtils::LeaveChaosMode() {
4244 ChaosMode::leaveChaosMode();
4245 return NS_OK;
4248 NS_IMETHODIMP
4249 nsDOMWindowUtils::TriggerDeviceReset() {
4250 if (!XRE_IsParentProcess()) {
4251 return NS_ERROR_NOT_AVAILABLE;
4254 GPUProcessManager* pm = GPUProcessManager::Get();
4255 if (pm) {
4256 pm->SimulateDeviceReset();
4258 return NS_OK;
4261 NS_IMETHODIMP
4262 nsDOMWindowUtils::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
4263 bool* aRetVal) {
4264 PresShell* presShell = GetPresShell();
4265 if (!presShell) {
4266 return NS_ERROR_FAILURE;
4269 return presShell->HasRuleProcessorUsedByMultipleStyleSets(aSheetType,
4270 aRetVal);
4273 NS_IMETHODIMP
4274 nsDOMWindowUtils::RespectDisplayPortSuppression(bool aEnabled) {
4275 RefPtr<PresShell> presShell = GetPresShell();
4276 presShell->RespectDisplayportSuppression(aEnabled);
4277 return NS_OK;
4280 NS_IMETHODIMP
4281 nsDOMWindowUtils::ForceReflowInterrupt() {
4282 nsPresContext* pc = GetPresContext();
4283 if (!pc) {
4284 return NS_ERROR_NOT_AVAILABLE;
4286 pc->SetPendingInterruptFromTest();
4287 return NS_OK;
4290 NS_IMETHODIMP
4291 nsDOMWindowUtils::TerminateGPUProcess() {
4292 GPUProcessManager* pm = GPUProcessManager::Get();
4293 if (pm) {
4294 pm->KillProcess();
4296 return NS_OK;
4299 NS_IMETHODIMP
4300 nsDOMWindowUtils::GetGpuProcessPid(int32_t* aPid) {
4301 GPUProcessManager* pm = GPUProcessManager::Get();
4302 if (pm) {
4303 *aPid = pm->GPUProcessPid();
4304 } else {
4305 *aPid = -1;
4308 return NS_OK;
4311 struct StateTableEntry {
4312 const char* mStateString;
4313 ElementState mState;
4316 static constexpr StateTableEntry kManuallyManagedStates[] = {
4317 {"autofill", ElementState::AUTOFILL},
4318 // :-moz-autofill-preview implies :autofill.
4319 {"-moz-autofill-preview",
4320 ElementState::AUTOFILL_PREVIEW | ElementState::AUTOFILL},
4321 {nullptr, ElementState()},
4324 static_assert(!kManuallyManagedStates[ArrayLength(kManuallyManagedStates) - 1]
4325 .mStateString,
4326 "last kManuallyManagedStates entry must be a sentinel with "
4327 "mStateString == nullptr");
4329 static ElementState GetEventStateForString(const nsAString& aStateString) {
4330 for (const StateTableEntry* entry = kManuallyManagedStates;
4331 entry->mStateString; ++entry) {
4332 if (aStateString.EqualsASCII(entry->mStateString)) {
4333 return entry->mState;
4336 return ElementState();
4339 NS_IMETHODIMP
4340 nsDOMWindowUtils::AddManuallyManagedState(Element* aElement,
4341 const nsAString& aStateString) {
4342 if (!aElement) {
4343 return NS_ERROR_INVALID_ARG;
4346 ElementState state = GetEventStateForString(aStateString);
4347 if (state.IsEmpty()) {
4348 return NS_ERROR_INVALID_ARG;
4351 aElement->AddStates(state);
4352 return NS_OK;
4355 NS_IMETHODIMP
4356 nsDOMWindowUtils::RemoveManuallyManagedState(Element* aElement,
4357 const nsAString& aStateString) {
4358 if (!aElement) {
4359 return NS_ERROR_INVALID_ARG;
4362 ElementState state = GetEventStateForString(aStateString);
4363 if (state.IsEmpty()) {
4364 return NS_ERROR_INVALID_ARG;
4367 aElement->RemoveStates(state);
4368 return NS_OK;
4371 NS_IMETHODIMP
4372 nsDOMWindowUtils::GetStorageUsage(Storage* aStorage, int64_t* aRetval) {
4373 if (!aStorage) {
4374 return NS_ERROR_UNEXPECTED;
4377 *aRetval = aStorage->GetOriginQuotaUsage();
4379 return NS_OK;
4382 NS_IMETHODIMP
4383 nsDOMWindowUtils::GetDirectionFromText(const nsAString& aString,
4384 int32_t* aRetval) {
4385 Directionality dir =
4386 ::GetDirectionFromText(aString.BeginReading(), aString.Length(), nullptr);
4387 switch (dir) {
4388 case Directionality::Unset:
4389 *aRetval = nsIDOMWindowUtils::DIRECTION_NOT_SET;
4390 break;
4391 case Directionality::Rtl:
4392 *aRetval = nsIDOMWindowUtils::DIRECTION_RTL;
4393 break;
4394 case Directionality::Ltr:
4395 *aRetval = nsIDOMWindowUtils::DIRECTION_LTR;
4396 break;
4397 case Directionality::Auto:
4398 MOZ_ASSERT_UNREACHABLE(
4399 "GetDirectionFromText should never return this value");
4400 return NS_ERROR_FAILURE;
4402 return NS_OK;
4405 NS_IMETHODIMP
4406 nsDOMWindowUtils::EnsureDirtyRootFrame() {
4407 Document* doc = GetDocument();
4408 PresShell* presShell = doc ? doc->GetPresShell() : nullptr;
4410 if (!presShell) {
4411 return NS_ERROR_FAILURE;
4414 nsIFrame* frame = presShell->GetRootFrame();
4415 if (!frame) {
4416 return NS_ERROR_FAILURE;
4419 presShell->FrameNeedsReflow(
4420 frame, IntrinsicDirty::FrameAncestorsAndDescendants, NS_FRAME_IS_DIRTY);
4421 return NS_OK;
4424 NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
4425 NS_INTERFACE_MAP_ENTRY(nsISupports)
4426 NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)
4427 NS_INTERFACE_MAP_END
4429 NS_IMPL_ADDREF(nsTranslationNodeList)
4430 NS_IMPL_RELEASE(nsTranslationNodeList)
4432 NS_IMETHODIMP
4433 nsTranslationNodeList::Item(uint32_t aIndex, nsINode** aRetVal) {
4434 NS_ENSURE_ARG_POINTER(aRetVal);
4435 NS_IF_ADDREF(*aRetVal = mNodes.SafeElementAt(aIndex));
4436 return NS_OK;
4439 NS_IMETHODIMP
4440 nsTranslationNodeList::IsTranslationRootAtIndex(uint32_t aIndex,
4441 bool* aRetVal) {
4442 NS_ENSURE_ARG_POINTER(aRetVal);
4443 if (aIndex >= mLength) {
4444 *aRetVal = false;
4445 return NS_OK;
4448 *aRetVal = mNodeIsRoot.ElementAt(aIndex);
4449 return NS_OK;
4452 NS_IMETHODIMP
4453 nsTranslationNodeList::GetLength(uint32_t* aRetVal) {
4454 NS_ENSURE_ARG_POINTER(aRetVal);
4455 *aRetVal = mLength;
4456 return NS_OK;
4459 NS_IMETHODIMP
4460 nsDOMWindowUtils::WrCapture() {
4461 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
4462 wrbc->Capture();
4464 return NS_OK;
4467 NS_IMETHODIMP
4468 nsDOMWindowUtils::WrStartCaptureSequence(const nsACString& aPath,
4469 uint32_t aFlags) {
4470 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
4471 wrbc->StartCaptureSequence(nsCString(aPath), aFlags);
4473 return NS_OK;
4476 NS_IMETHODIMP
4477 nsDOMWindowUtils::WrStopCaptureSequence() {
4478 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
4479 wrbc->StopCaptureSequence();
4481 return NS_OK;
4484 NS_IMETHODIMP
4485 nsDOMWindowUtils::SetCompositionRecording(bool aValue, Promise** aOutPromise) {
4486 return aValue ? StartCompositionRecording(aOutPromise)
4487 : StopCompositionRecording(true, aOutPromise);
4490 NS_IMETHODIMP
4491 nsDOMWindowUtils::StartCompositionRecording(Promise** aOutPromise) {
4492 NS_ENSURE_ARG(aOutPromise);
4493 *aOutPromise = nullptr;
4495 nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow);
4496 NS_ENSURE_STATE(outer);
4497 nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
4498 NS_ENSURE_STATE(inner);
4500 ErrorResult err;
4501 RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err);
4502 if (NS_WARN_IF(err.Failed())) {
4503 return err.StealNSResult();
4506 CompositorBridgeChild* cbc = GetCompositorBridge();
4507 if (NS_WARN_IF(!cbc)) {
4508 promise->MaybeReject(NS_ERROR_UNEXPECTED);
4509 } else {
4510 cbc->SendBeginRecording(TimeStamp::Now())
4511 ->Then(
4512 GetCurrentSerialEventTarget(), __func__,
4513 [promise](const bool& aSuccess) {
4514 if (aSuccess) {
4515 promise->MaybeResolve(true);
4516 } else {
4517 promise->MaybeRejectWithInvalidStateError(
4518 "The composition recorder is already running.");
4521 [promise](const mozilla::ipc::ResponseRejectReason&) {
4522 promise->MaybeRejectWithInvalidStateError(
4523 "Could not start the composition recorder.");
4527 promise.forget(aOutPromise);
4528 return NS_OK;
4531 static bool WriteRecordingToDisk(const FrameRecording& aRecording,
4532 double aUnixStartMS) {
4533 // The directory name contains the unix timestamp for when recording started,
4534 // because we want the consumer of these files to be able to compute an
4535 // absolute timestamp of each screenshot. That allows them to align
4536 // screenshots with timed data from other sources, such as Gecko profiler
4537 // information. The time of each screenshot is part of the screenshot's
4538 // filename, expressed as milliseconds from the recording start.
4539 std::stringstream recordingDirectory;
4540 recordingDirectory << gfxVars::LayersWindowRecordingPath()
4541 << "windowrecording-" << int64_t(aUnixStartMS);
4543 #ifdef XP_WIN
4544 _mkdir(recordingDirectory.str().c_str());
4545 #else
4546 mkdir(recordingDirectory.str().c_str(), 0777);
4547 #endif
4549 auto byteSpan = aRecording.bytes().AsSpan();
4551 uint32_t i = 1;
4553 for (const auto& frame : aRecording.frames()) {
4554 const uint32_t frameBufferLength = frame.length();
4555 if (frameBufferLength > byteSpan.Length()) {
4556 return false;
4559 const auto frameSpan = byteSpan.To(frameBufferLength);
4560 byteSpan = byteSpan.From(frameBufferLength);
4562 const double frameTimeMS =
4563 (frame.timeOffset() - aRecording.startTime()).ToMilliseconds();
4565 std::stringstream filename;
4566 filename << recordingDirectory.str() << "/frame-" << i << "-"
4567 << uint32_t(frameTimeMS) << ".png";
4569 FILE* file = fopen(filename.str().c_str(), "wb");
4570 if (!file) {
4571 return false;
4574 const size_t bytesWritten =
4575 fwrite(frameSpan.Elements(), sizeof(uint8_t), frameSpan.Length(), file);
4577 fclose(file);
4579 if (bytesWritten < frameSpan.Length()) {
4580 return false;
4583 ++i;
4586 return byteSpan.Length() == 0;
4589 static Maybe<DOMCollectedFrames> ConvertCompositionRecordingFramesToDom(
4590 const FrameRecording& aRecording, double aUnixStartMS) {
4591 auto byteSpan = aRecording.bytes().AsSpan();
4593 nsTArray<DOMCollectedFrame> domFrames;
4595 for (const auto& recordedFrame : aRecording.frames()) {
4596 const uint32_t frameBufferLength = recordedFrame.length();
4597 if (frameBufferLength > byteSpan.Length()) {
4598 return Nothing();
4601 const auto frameSpan = byteSpan.To(frameBufferLength);
4602 byteSpan = byteSpan.From(frameBufferLength);
4604 nsCString dataUri;
4606 dataUri.AppendLiteral("data:image/png;base64,");
4608 nsresult rv =
4609 Base64EncodeAppend(reinterpret_cast<const char*>(frameSpan.Elements()),
4610 frameSpan.Length(), dataUri);
4611 if (NS_FAILED(rv)) {
4612 return Nothing();
4615 DOMCollectedFrame domFrame;
4616 domFrame.mTimeOffset =
4617 (recordedFrame.timeOffset() - aRecording.startTime()).ToMilliseconds();
4618 domFrame.mDataUri = std::move(dataUri);
4620 domFrames.AppendElement(std::move(domFrame));
4623 if (byteSpan.Length() != 0) {
4624 return Nothing();
4627 DOMCollectedFrames result;
4629 result.mRecordingStart = aUnixStartMS;
4630 result.mFrames = std::move(domFrames);
4632 return Some(std::move(result));
4635 NS_IMETHODIMP
4636 nsDOMWindowUtils::StopCompositionRecording(bool aWriteToDisk,
4637 Promise** aOutPromise) {
4638 NS_ENSURE_ARG_POINTER(aOutPromise);
4639 *aOutPromise = nullptr;
4641 nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow);
4642 NS_ENSURE_STATE(outer);
4643 nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
4644 NS_ENSURE_STATE(inner);
4646 ErrorResult err;
4647 RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err);
4648 if (NS_WARN_IF(err.Failed())) {
4649 return err.StealNSResult();
4652 RefPtr<Promise>(promise).forget(aOutPromise);
4654 CompositorBridgeChild* cbc = GetCompositorBridge();
4655 if (NS_WARN_IF(!cbc)) {
4656 promise->MaybeReject(NS_ERROR_UNEXPECTED);
4657 return NS_OK;
4660 cbc->SendEndRecording()->Then(
4661 GetCurrentSerialEventTarget(), __func__,
4662 [promise, aWriteToDisk](Maybe<FrameRecording>&& aRecording) {
4663 if (!aRecording) {
4664 promise->MaybeRejectWithUnknownError("Failed to get frame recording");
4665 return;
4668 // We need to know when the recording started in Unix Time.
4669 // Unfortunately, the recording start time is an opaque Timestamp that
4670 // can only be used to calculate a duration.
4672 // This is not great, but we are going to get Now() twice in close
4673 // proximity, one in Unix Time and the other in Timestamp time. Then we
4674 // can subtract the length of the recording from the current Unix Time
4675 // to get the Unix start time.
4676 const TimeStamp timestampNow = TimeStamp::Now();
4677 const int64_t unixNowUS = PR_Now();
4679 const TimeDuration recordingLength =
4680 timestampNow - aRecording->startTime();
4681 const double unixNowMS = double(unixNowUS) / 1000.0;
4682 const double unixStartMS = unixNowMS - recordingLength.ToMilliseconds();
4684 if (aWriteToDisk) {
4685 if (!WriteRecordingToDisk(*aRecording, unixStartMS)) {
4686 promise->MaybeRejectWithUnknownError(
4687 "Failed to write recording to disk");
4688 return;
4690 promise->MaybeResolveWithUndefined();
4691 } else {
4692 auto maybeDomFrames =
4693 ConvertCompositionRecordingFramesToDom(*aRecording, unixStartMS);
4694 if (!maybeDomFrames) {
4695 promise->MaybeRejectWithUnknownError(
4696 "Unable to base64-encode recorded frames");
4697 return;
4699 promise->MaybeResolve(*maybeDomFrames);
4702 [promise](const mozilla::ipc::ResponseRejectReason&) {
4703 promise->MaybeRejectWithUnknownError(
4704 "IPC failed getting composition recording");
4707 return NS_OK;
4710 NS_IMETHODIMP
4711 nsDOMWindowUtils::SetSystemFont(const nsACString& aFontName) {
4712 nsIWidget* widget = GetWidget();
4713 if (!widget) {
4714 return NS_OK;
4717 nsAutoCString fontName(aFontName);
4718 return widget->SetSystemFont(fontName);
4721 NS_IMETHODIMP
4722 nsDOMWindowUtils::GetSystemFont(nsACString& aFontName) {
4723 nsIWidget* widget = GetWidget();
4724 if (!widget) {
4725 return NS_OK;
4728 nsAutoCString fontName;
4729 widget->GetSystemFont(fontName);
4730 aFontName.Assign(fontName);
4731 return NS_OK;
4734 NS_IMETHODIMP
4735 nsDOMWindowUtils::IsCssPropertyRecordedInUseCounter(const nsACString& aPropName,
4736 bool* aRecorded) {
4737 *aRecorded = false;
4739 Document* doc = GetDocument();
4740 if (!doc || !doc->GetStyleUseCounters()) {
4741 return NS_ERROR_FAILURE;
4744 bool knownProp = false;
4745 *aRecorded = Servo_IsCssPropertyRecordedInUseCounter(
4746 doc->GetStyleUseCounters(), &aPropName, &knownProp);
4747 return knownProp ? NS_OK : NS_ERROR_FAILURE;
4750 NS_IMETHODIMP
4751 nsDOMWindowUtils::IsCoepCredentialless(bool* aResult) {
4752 Document* doc = GetDocument();
4753 if (!doc) {
4754 return NS_ERROR_FAILURE;
4757 *aResult = net::IsCoepCredentiallessEnabled(
4758 doc->Trials().IsEnabled(OriginTrial::CoepCredentialless));
4759 return NS_OK;
4762 NS_IMETHODIMP
4763 nsDOMWindowUtils::GetLayersId(uint64_t* aOutLayersId) {
4764 nsIWidget* widget = GetWidget();
4765 if (!widget) {
4766 return NS_ERROR_FAILURE;
4768 BrowserChild* child = widget->GetOwningBrowserChild();
4769 if (!child) {
4770 return NS_ERROR_FAILURE;
4772 *aOutLayersId = (uint64_t)child->GetLayersId();
4773 return NS_OK;
4776 NS_IMETHODIMP
4777 nsDOMWindowUtils::GetPaintCount(uint64_t* aPaintCount) {
4778 auto* presShell = GetPresShell();
4779 *aPaintCount = presShell ? presShell->GetPaintCount() : 0;
4780 return NS_OK;
4783 NS_IMETHODIMP
4784 nsDOMWindowUtils::GetWebrtcRawDeviceId(nsAString& aRawDeviceId) {
4785 if (!XRE_IsParentProcess()) {
4786 MOZ_CRASH(
4787 "GetWebrtcRawDeviceId is only available in the parent "
4788 "process");
4791 nsIWidget* widget = GetWidget();
4792 if (!widget) {
4793 return NS_ERROR_FAILURE;
4796 int64_t rawDeviceId =
4797 (int64_t)(widget->GetNativeData(NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID));
4798 if (!rawDeviceId) {
4799 return NS_ERROR_FAILURE;
4802 aRawDeviceId.AppendInt(rawDeviceId);
4803 return NS_OK;
4806 NS_IMETHODIMP
4807 nsDOMWindowUtils::GetEffectivelyThrottlesFrameRequests(bool* aResult) {
4808 Document* doc = GetDocument();
4809 if (!doc) {
4810 return NS_ERROR_FAILURE;
4812 *aResult = !doc->WouldScheduleFrameRequestCallbacks() ||
4813 doc->ShouldThrottleFrameRequests();
4814 return NS_OK;
4817 NS_IMETHODIMP
4818 nsDOMWindowUtils::ResetMobileViewportManager() {
4819 if (RefPtr<PresShell> presShell = GetPresShell()) {
4820 if (auto mvm = presShell->GetMobileViewportManager()) {
4821 mvm->SetInitialViewport();
4822 return NS_OK;
4825 // Unable to reset, so let's error out
4826 return NS_ERROR_FAILURE;
4829 NS_IMETHODIMP
4830 nsDOMWindowUtils::GetSuspendedByBrowsingContextGroup(bool* aResult) {
4831 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
4832 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
4834 nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
4835 NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE);
4837 *aResult = inner->GetWasSuspendedByGroup();
4838 return NS_OK;
4841 NS_IMETHODIMP
4842 nsDOMWindowUtils::GetHasScrollLinkedEffect(bool* aResult) {
4843 Document* doc = GetDocument();
4844 if (!doc) {
4845 return NS_ERROR_FAILURE;
4847 *aResult = doc->HasScrollLinkedEffect();
4848 return NS_OK;
4851 NS_IMETHODIMP
4852 nsDOMWindowUtils::GetOrientationLock(uint32_t* aOrientationLock) {
4853 NS_WARNING("nsDOMWindowUtils::GetOrientationLock");
4855 nsIDocShell* docShell = GetDocShell();
4856 if (!docShell) {
4857 return NS_ERROR_FAILURE;
4860 BrowsingContext* bc = docShell->GetBrowsingContext();
4861 bc = bc ? bc->Top() : nullptr;
4862 if (!bc) {
4863 return NS_ERROR_FAILURE;
4866 *aOrientationLock = static_cast<uint32_t>(bc->GetOrientationLock());
4867 return NS_OK;
4870 NS_IMETHODIMP
4871 nsDOMWindowUtils::GetWheelScrollTarget(Element** aResult) {
4872 *aResult = nullptr;
4873 if (nsIFrame* targetFrame = WheelTransaction::GetScrollTargetFrame()) {
4874 NS_IF_ADDREF(*aResult = Element::FromNodeOrNull(targetFrame->GetContent()));
4876 return NS_OK;
4879 NS_IMETHODIMP
4880 nsDOMWindowUtils::SetHiDPIMode(bool aHiDPI) {
4881 #ifdef DEBUG
4882 nsCOMPtr<nsIWidget> widget = GetWidget();
4883 if (!widget) return NS_ERROR_FAILURE;
4885 return widget->SetHiDPIMode(aHiDPI);
4886 #else
4887 return NS_ERROR_NOT_AVAILABLE;
4888 #endif
4891 NS_IMETHODIMP
4892 nsDOMWindowUtils::RestoreHiDPIMode() {
4893 #ifdef DEBUG
4894 nsCOMPtr<nsIWidget> widget = GetWidget();
4895 if (!widget) return NS_ERROR_FAILURE;
4897 return widget->RestoreHiDPIMode();
4898 #else
4899 return NS_ERROR_NOT_AVAILABLE;
4900 #endif