Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / base / nsDOMWindowUtils.cpp
blob46d1a8a805f5cd2cca81205ed7ec5b718b761576
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/DOMCollectedFramesBinding.h"
28 #include "mozilla/dom/Event.h"
29 #include "mozilla/dom/Touch.h"
30 #include "mozilla/dom/UserActivation.h"
31 #include "mozilla/EventStateManager.h"
32 #include "mozilla/PendingAnimationTracker.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"
137 #ifdef XP_WIN
138 # include <direct.h>
139 #else
140 # include <sys/stat.h>
141 #endif
143 #ifdef XP_WIN
144 # undef GetClassName
145 #endif
147 using namespace mozilla;
148 using namespace mozilla::dom;
149 using namespace mozilla::ipc;
150 using namespace mozilla::layers;
151 using namespace mozilla::widget;
152 using namespace mozilla::gfx;
154 class gfxContext;
156 class OldWindowSize : public LinkedListElement<OldWindowSize> {
157 public:
158 static void Set(nsIWeakReference* aWindowRef, const nsSize& aSize) {
159 OldWindowSize* item = GetItem(aWindowRef);
160 if (item) {
161 item->mSize = aSize;
162 } else {
163 item = new OldWindowSize(aWindowRef, aSize);
164 sList.insertBack(item);
168 static nsSize GetAndRemove(nsIWeakReference* aWindowRef) {
169 nsSize result;
170 if (OldWindowSize* item = GetItem(aWindowRef)) {
171 result = item->mSize;
172 delete item;
174 return result;
177 private:
178 explicit OldWindowSize(nsIWeakReference* aWindowRef, const nsSize& aSize)
179 : mWindowRef(aWindowRef), mSize(aSize) {}
180 ~OldWindowSize() = default;
183 static OldWindowSize* GetItem(nsIWeakReference* aWindowRef) {
184 OldWindowSize* item = sList.getFirst();
185 while (item && item->mWindowRef != aWindowRef) {
186 item = item->getNext();
188 return item;
191 static LinkedList<OldWindowSize> sList;
192 nsWeakPtr mWindowRef;
193 nsSize mSize;
196 namespace {
198 class NativeInputRunnable final : public PrioritizableRunnable {
199 explicit NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent);
200 ~NativeInputRunnable() = default;
202 public:
203 static already_AddRefed<nsIRunnable> Create(
204 already_AddRefed<nsIRunnable>&& aEvent);
207 NativeInputRunnable::NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent)
208 : PrioritizableRunnable(std::move(aEvent),
209 nsIRunnablePriority::PRIORITY_INPUT_HIGH) {}
211 /* static */
212 already_AddRefed<nsIRunnable> NativeInputRunnable::Create(
213 already_AddRefed<nsIRunnable>&& aEvent) {
214 MOZ_ASSERT(NS_IsMainThread());
215 nsCOMPtr<nsIRunnable> event(new NativeInputRunnable(std::move(aEvent)));
216 return event.forget();
219 } // unnamed namespace
221 LinkedList<OldWindowSize> OldWindowSize::sList;
223 NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
224 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWindowUtils)
225 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowUtils)
226 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
227 NS_INTERFACE_MAP_END
229 NS_IMPL_ADDREF(nsDOMWindowUtils)
230 NS_IMPL_RELEASE(nsDOMWindowUtils)
232 nsDOMWindowUtils::nsDOMWindowUtils(nsGlobalWindowOuter* aWindow) {
233 nsCOMPtr<nsISupports> supports = do_QueryObject(aWindow);
234 mWindow = do_GetWeakReference(supports);
237 nsDOMWindowUtils::~nsDOMWindowUtils() { OldWindowSize::GetAndRemove(mWindow); }
239 nsIDocShell* nsDOMWindowUtils::GetDocShell() {
240 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
241 if (!window) {
242 return nullptr;
244 return window->GetDocShell();
247 PresShell* nsDOMWindowUtils::GetPresShell() {
248 nsIDocShell* docShell = GetDocShell();
249 if (!docShell) {
250 return nullptr;
252 return docShell->GetPresShell();
255 nsPresContext* nsDOMWindowUtils::GetPresContext() {
256 nsIDocShell* docShell = GetDocShell();
257 if (!docShell) {
258 return nullptr;
260 return docShell->GetPresContext();
263 Document* nsDOMWindowUtils::GetDocument() {
264 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
265 if (!window) {
266 return nullptr;
268 return window->GetExtantDoc();
271 WebRenderBridgeChild* nsDOMWindowUtils::GetWebRenderBridge() {
272 if (nsIWidget* widget = GetWidget()) {
273 if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
274 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
275 return wr->WrBridge();
279 return nullptr;
282 CompositorBridgeChild* nsDOMWindowUtils::GetCompositorBridge() {
283 if (nsIWidget* widget = GetWidget()) {
284 if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
285 if (CompositorBridgeChild* cbc = renderer->GetCompositorBridgeChild()) {
286 return cbc;
290 return nullptr;
293 NS_IMETHODIMP
294 nsDOMWindowUtils::GetLastOverWindowPointerLocationInCSSPixels(float* aX,
295 float* aY) {
296 const PresShell* presShell = GetPresShell();
297 const nsPresContext* presContext = GetPresContext();
299 if (!presShell || !presContext) {
300 return NS_ERROR_FAILURE;
303 const nsPoint& lastOverWindowPointerLocation =
304 presShell->GetLastOverWindowPointerLocation();
306 if (lastOverWindowPointerLocation.X() == NS_UNCONSTRAINEDSIZE &&
307 lastOverWindowPointerLocation.Y() == NS_UNCONSTRAINEDSIZE) {
308 *aX = 0;
309 *aY = 0;
310 } else {
311 const CSSPoint lastOverWindowPointerLocationInCSSPixels =
312 CSSPoint::FromAppUnits(lastOverWindowPointerLocation);
313 *aX = lastOverWindowPointerLocationInCSSPixels.X();
314 *aY = lastOverWindowPointerLocationInCSSPixels.Y();
317 return NS_OK;
320 NS_IMETHODIMP
321 nsDOMWindowUtils::SyncFlushCompositor() {
322 if (nsIWidget* widget = GetWidget()) {
323 if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
324 if (KnowsCompositor* kc = renderer->AsKnowsCompositor()) {
325 kc->SyncWithCompositor();
329 return NS_OK;
332 NS_IMETHODIMP
333 nsDOMWindowUtils::GetImageAnimationMode(uint16_t* aMode) {
334 NS_ENSURE_ARG_POINTER(aMode);
335 *aMode = 0;
336 nsPresContext* presContext = GetPresContext();
337 if (presContext) {
338 *aMode = presContext->ImageAnimationMode();
339 return NS_OK;
341 return NS_ERROR_NOT_AVAILABLE;
344 NS_IMETHODIMP
345 nsDOMWindowUtils::SetImageAnimationMode(uint16_t aMode) {
346 nsPresContext* presContext = GetPresContext();
347 if (presContext) {
348 presContext->SetImageAnimationMode(aMode);
349 return NS_OK;
351 return NS_ERROR_NOT_AVAILABLE;
354 NS_IMETHODIMP
355 nsDOMWindowUtils::GetDocCharsetIsForced(bool* aIsForced) {
356 *aIsForced = false;
358 Document* doc = GetDocument();
359 if (doc) {
360 auto source = doc->GetDocumentCharacterSetSource();
361 *aIsForced = source == kCharsetFromInitialUserForcedAutoDetection ||
362 source == kCharsetFromFinalUserForcedAutoDetection;
364 return NS_OK;
367 NS_IMETHODIMP
368 nsDOMWindowUtils::GetPhysicalMillimeterInCSSPixels(float* aPhysicalMillimeter) {
369 nsPresContext* presContext = GetPresContext();
370 if (!presContext) {
371 return NS_ERROR_NOT_AVAILABLE;
374 *aPhysicalMillimeter = nsPresContext::AppUnitsToFloatCSSPixels(
375 presContext->PhysicalMillimetersToAppUnits(1));
376 return NS_OK;
379 NS_IMETHODIMP
380 nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName,
381 nsAString& aValue) {
382 Document* doc = GetDocument();
383 if (doc) {
384 RefPtr<nsAtom> name = NS_Atomize(aName);
385 doc->GetHeaderData(name, aValue);
386 return NS_OK;
389 aValue.Truncate();
390 return NS_OK;
393 NS_IMETHODIMP
394 nsDOMWindowUtils::UpdateLayerTree() {
395 if (RefPtr<PresShell> presShell = GetPresShell()) {
396 // Don't flush throttled animations since it might fire MozAfterPaint event
397 // (in WebRender it constantly does), thus the reftest harness can't take
398 // any snapshot until the throttled animations finished.
399 presShell->FlushPendingNotifications(
400 ChangesToFlush(FlushType::Display, false /* flush animations */));
401 RefPtr<nsViewManager> vm = presShell->GetViewManager();
402 if (nsView* view = vm->GetRootView()) {
403 nsAutoScriptBlocker scriptBlocker;
404 presShell->PaintAndRequestComposite(view,
405 PaintFlags::PaintSyncDecodeImages);
406 presShell->GetWindowRenderer()->WaitOnTransactionProcessed();
409 return NS_OK;
412 NS_IMETHODIMP
413 nsDOMWindowUtils::GetContentViewerSize(uint32_t* aDisplayWidth,
414 uint32_t* aDisplayHeight) {
415 PresShell* presShell = GetPresShell();
416 LayoutDeviceIntSize displaySize;
418 if (!presShell || !nsLayoutUtils::GetContentViewerSize(
419 presShell->GetPresContext(), displaySize)) {
420 return NS_ERROR_FAILURE;
423 *aDisplayWidth = displaySize.width;
424 *aDisplayHeight = displaySize.height;
426 return NS_OK;
429 NS_IMETHODIMP
430 nsDOMWindowUtils::GetViewportInfo(uint32_t aDisplayWidth,
431 uint32_t aDisplayHeight, double* aDefaultZoom,
432 bool* aAllowZoom, double* aMinZoom,
433 double* aMaxZoom, uint32_t* aWidth,
434 uint32_t* aHeight, bool* aAutoSize) {
435 Document* doc = GetDocument();
436 NS_ENSURE_STATE(doc);
438 nsViewportInfo info =
439 doc->GetViewportInfo(ScreenIntSize(aDisplayWidth, aDisplayHeight));
440 *aDefaultZoom = info.GetDefaultZoom().scale;
441 *aAllowZoom = info.IsZoomAllowed();
442 *aMinZoom = info.GetMinZoom().scale;
443 *aMaxZoom = info.GetMaxZoom().scale;
444 CSSIntSize size = gfx::RoundedToInt(info.GetSize());
445 *aWidth = size.width;
446 *aHeight = size.height;
447 *aAutoSize = info.IsAutoSizeEnabled();
448 return NS_OK;
451 NS_IMETHODIMP
452 nsDOMWindowUtils::GetViewportFitInfo(nsAString& aViewportFit) {
453 Document* doc = GetDocument();
454 NS_ENSURE_STATE(doc);
456 ViewportMetaData metaData = doc->GetViewportMetaData();
457 if (metaData.mViewportFit.EqualsLiteral("contain")) {
458 aViewportFit.AssignLiteral("contain");
459 } else if (metaData.mViewportFit.EqualsLiteral("cover")) {
460 aViewportFit.AssignLiteral("cover");
461 } else {
462 aViewportFit.AssignLiteral("auto");
464 return NS_OK;
467 NS_IMETHODIMP
468 nsDOMWindowUtils::SetMousewheelAutodir(Element* aElement, bool aEnabled,
469 bool aHonourRoot) {
470 aElement->SetProperty(nsGkAtoms::forceMousewheelAutodir,
471 reinterpret_cast<void*>(aEnabled));
472 aElement->SetProperty(nsGkAtoms::forceMousewheelAutodirHonourRoot,
473 reinterpret_cast<void*>(aHonourRoot));
474 return NS_OK;
477 NS_IMETHODIMP
478 nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
479 float aWidthPx, float aHeightPx,
480 Element* aElement,
481 uint32_t aPriority) {
482 PresShell* presShell = GetPresShell();
483 if (!presShell) {
484 return NS_ERROR_FAILURE;
487 if (!aElement) {
488 return NS_ERROR_INVALID_ARG;
491 if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
492 return NS_ERROR_INVALID_ARG;
495 bool hadDisplayPort = false;
496 bool wasPainted = false;
497 nsRect oldDisplayPort;
499 DisplayPortPropertyData* currentData =
500 static_cast<DisplayPortPropertyData*>(
501 aElement->GetProperty(nsGkAtoms::DisplayPort));
502 if (currentData) {
503 if (currentData->mPriority > aPriority) {
504 return NS_OK;
506 hadDisplayPort = true;
507 oldDisplayPort = currentData->mRect;
508 wasPainted = currentData->mPainted;
512 nsRect displayport(nsPresContext::CSSPixelsToAppUnits(aXPx),
513 nsPresContext::CSSPixelsToAppUnits(aYPx),
514 nsPresContext::CSSPixelsToAppUnits(aWidthPx),
515 nsPresContext::CSSPixelsToAppUnits(aHeightPx));
517 aElement->RemoveProperty(nsGkAtoms::MinimalDisplayPort);
518 aElement->SetProperty(
519 nsGkAtoms::DisplayPort,
520 new DisplayPortPropertyData(displayport, aPriority, wasPainted),
521 nsINode::DeleteProperty<DisplayPortPropertyData>);
523 DisplayPortUtils::InvalidateForDisplayPortChange(aElement, hadDisplayPort,
524 oldDisplayPort, displayport);
526 nsIFrame* rootFrame = presShell->GetRootFrame();
527 if (rootFrame) {
528 rootFrame->SchedulePaint();
530 // If we are hiding something that is a display root then send empty paint
531 // transaction in order to release retained layers because it won't get
532 // any more paint requests when it is hidden.
533 if (displayport.IsEmpty() &&
534 rootFrame == nsLayoutUtils::GetDisplayRootFrame(rootFrame)) {
535 nsCOMPtr<nsIWidget> widget = GetWidget();
536 if (widget) {
537 using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
538 nsLayoutUtils::PaintFrame(
539 nullptr, rootFrame, nsRegion(), NS_RGB(255, 255, 255),
540 nsDisplayListBuilderMode::Painting, PaintFrameFlags::WidgetLayers);
545 return NS_OK;
548 NS_IMETHODIMP
549 nsDOMWindowUtils::SetDisplayPortMarginsForElement(
550 float aLeftMargin, float aTopMargin, float aRightMargin,
551 float aBottomMargin, Element* aElement, uint32_t aPriority) {
552 PresShell* presShell = GetPresShell();
553 if (!presShell) {
554 return NS_ERROR_FAILURE;
557 if (!aElement) {
558 return NS_ERROR_INVALID_ARG;
561 if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
562 return NS_ERROR_INVALID_ARG;
565 // Note order change of arguments between our function signature and
566 // ScreenMargin constructor.
567 ScreenMargin displayportMargins(aTopMargin, aRightMargin, aBottomMargin,
568 aLeftMargin);
570 DisplayPortUtils::SetDisplayPortMargins(
571 aElement, presShell,
572 DisplayPortMargins::ForContent(aElement, displayportMargins),
573 DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes, aPriority);
575 return NS_OK;
578 NS_IMETHODIMP
579 nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX, int32_t aY,
580 int32_t aWidth, int32_t aHeight,
581 Element* aElement) {
582 PresShell* presShell = GetPresShell();
583 if (!presShell) {
584 return NS_ERROR_FAILURE;
587 if (!aElement) {
588 return NS_ERROR_INVALID_ARG;
591 if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
592 return NS_ERROR_INVALID_ARG;
595 DisplayPortUtils::SetDisplayPortBase(aElement,
596 nsRect(aX, aY, aWidth, aHeight));
598 return NS_OK;
601 NS_IMETHODIMP
602 nsDOMWindowUtils::GetScrollbarSizes(Element* aElement,
603 uint32_t* aOutVerticalScrollbarWidth,
604 uint32_t* aOutHorizontalScrollbarHeight) {
605 nsIScrollableFrame* scrollFrame =
606 nsLayoutUtils::FindScrollableFrameFor(aElement);
607 if (!scrollFrame) {
608 return NS_ERROR_INVALID_ARG;
611 CSSIntMargin scrollbarSizes =
612 RoundedToInt(CSSMargin::FromAppUnits(scrollFrame->GetActualScrollbarSizes(
613 nsIScrollableFrame::ScrollbarSizesOptions::
614 INCLUDE_VISUAL_VIEWPORT_SCROLLBARS)));
615 *aOutVerticalScrollbarWidth = scrollbarSizes.LeftRight();
616 *aOutHorizontalScrollbarHeight = scrollbarSizes.TopBottom();
618 return NS_OK;
621 NS_IMETHODIMP
622 nsDOMWindowUtils::SetResolutionAndScaleTo(float aResolution) {
623 PresShell* presShell = GetPresShell();
624 if (!presShell) {
625 return NS_ERROR_FAILURE;
628 presShell->SetResolutionAndScaleTo(aResolution, ResolutionChangeOrigin::Test);
630 return NS_OK;
633 NS_IMETHODIMP
634 nsDOMWindowUtils::SetRestoreResolution(float aResolution,
635 uint32_t aDisplayWidth,
636 uint32_t aDisplayHeight) {
637 PresShell* presShell = GetPresShell();
638 if (!presShell) {
639 return NS_ERROR_FAILURE;
642 presShell->SetRestoreResolution(
643 aResolution, LayoutDeviceIntSize(aDisplayWidth, aDisplayHeight));
645 return NS_OK;
648 NS_IMETHODIMP
649 nsDOMWindowUtils::GetResolution(float* aResolution) {
650 PresShell* presShell = GetPresShell();
651 if (!presShell) {
652 return NS_ERROR_FAILURE;
655 *aResolution = presShell->GetResolution();
657 return NS_OK;
660 NS_IMETHODIMP
661 nsDOMWindowUtils::SetIsFirstPaint(bool aIsFirstPaint) {
662 if (PresShell* presShell = GetPresShell()) {
663 presShell->SetIsFirstPaint(aIsFirstPaint);
664 return NS_OK;
666 return NS_ERROR_FAILURE;
669 NS_IMETHODIMP
670 nsDOMWindowUtils::GetIsFirstPaint(bool* aIsFirstPaint) {
671 if (PresShell* presShell = GetPresShell()) {
672 *aIsFirstPaint = presShell->GetIsFirstPaint();
673 return NS_OK;
675 return NS_ERROR_FAILURE;
678 NS_IMETHODIMP
679 nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) {
680 if (PresShell* presShell = GetPresShell()) {
681 *aPresShellId = presShell->GetPresShellId();
682 return NS_OK;
684 return NS_ERROR_FAILURE;
687 NS_IMETHODIMP
688 nsDOMWindowUtils::SendMouseEvent(
689 const nsAString& aType, float aX, float aY, int32_t aButton,
690 int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
691 float aPressure, unsigned short aInputSourceArg,
692 bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized,
693 int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount,
694 bool* aPreventDefault) {
695 return SendMouseEventCommon(
696 aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame,
697 aPressure, aInputSourceArg,
698 aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false,
699 aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true,
700 aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false,
701 aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED);
704 NS_IMETHODIMP
705 nsDOMWindowUtils::SendMouseEventToWindow(
706 const nsAString& aType, float aX, float aY, int32_t aButton,
707 int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
708 float aPressure, unsigned short aInputSourceArg,
709 bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized,
710 int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount) {
711 AUTO_PROFILER_LABEL("nsDOMWindowUtils::SendMouseEventToWindow", OTHER);
713 return SendMouseEventCommon(
714 aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame,
715 aPressure, aInputSourceArg,
716 aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true,
717 nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true,
718 aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false,
719 aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED);
722 NS_IMETHODIMP
723 nsDOMWindowUtils::SendMouseEventCommon(
724 const nsAString& aType, float aX, float aY, int32_t aButton,
725 int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
726 float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId,
727 bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized,
728 bool aIsWidgetEventSynthesized, int32_t aButtons) {
729 RefPtr<PresShell> presShell = GetPresShell();
730 PreventDefaultResult preventDefaultResult;
731 nsresult rv = nsContentUtils::SendMouseEvent(
732 presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers,
733 aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow,
734 &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized);
736 if (aPreventDefault) {
737 *aPreventDefault = preventDefaultResult != PreventDefaultResult::No;
740 return rv;
743 NS_IMETHODIMP
744 nsDOMWindowUtils::IsCORSSafelistedRequestHeader(const nsACString& aName,
745 const nsACString& aValue,
746 bool* aRetVal) {
747 NS_ENSURE_ARG_POINTER(aRetVal);
748 *aRetVal = nsContentUtils::IsCORSSafelistedRequestHeader(aName, aValue);
749 return NS_OK;
752 NS_IMETHODIMP
753 nsDOMWindowUtils::SendWheelEvent(float aX, float aY, double aDeltaX,
754 double aDeltaY, double aDeltaZ,
755 uint32_t aDeltaMode, int32_t aModifiers,
756 int32_t aLineOrPageDeltaX,
757 int32_t aLineOrPageDeltaY, uint32_t aOptions) {
758 // get the widget to send the event to
759 nsPoint offset;
760 nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
761 if (!widget) {
762 return NS_ERROR_NULL_POINTER;
765 WidgetWheelEvent wheelEvent(true, eWheel, widget);
766 wheelEvent.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
767 wheelEvent.mDeltaX = aDeltaX;
768 wheelEvent.mDeltaY = aDeltaY;
769 wheelEvent.mDeltaZ = aDeltaZ;
770 wheelEvent.mDeltaMode = aDeltaMode;
771 wheelEvent.mIsMomentum = (aOptions & WHEEL_EVENT_CAUSED_BY_MOMENTUM) != 0;
772 wheelEvent.mIsNoLineOrPageDelta =
773 (aOptions & WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE) != 0;
774 wheelEvent.mCustomizedByUserPrefs =
775 (aOptions & WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS) != 0;
776 wheelEvent.mLineOrPageDeltaX = aLineOrPageDeltaX;
777 wheelEvent.mLineOrPageDeltaY = aLineOrPageDeltaY;
779 nsPresContext* presContext = GetPresContext();
780 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
782 wheelEvent.mRefPoint =
783 nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
785 if (StaticPrefs::test_events_async_enabled() &&
786 StaticPrefs::test_events_async_wheel_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.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
902 nsPresContext* presContext = GetPresContext();
903 if (!presContext) {
904 return NS_ERROR_FAILURE;
906 uint32_t count = aIdentifiers.Length();
907 if (aXs.Length() != count || aYs.Length() != count ||
908 aRxs.Length() != count || aRys.Length() != count ||
909 aRotationAngles.Length() != count || aForces.Length() != count) {
910 return NS_ERROR_INVALID_ARG;
912 event.mTouches.SetCapacity(count);
913 for (uint32_t i = 0; i < count; ++i) {
914 LayoutDeviceIntPoint pt = nsContentUtils::ToWidgetPoint(
915 CSSPoint(aXs[i], aYs[i]), offset, presContext);
916 LayoutDeviceIntPoint radius = LayoutDeviceIntPoint::FromAppUnitsRounded(
917 CSSPoint::ToAppUnits(CSSPoint(aRxs[i], aRys[i])),
918 presContext->AppUnitsPerDevPixel());
920 RefPtr<Touch> t = new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i],
921 aForces[i], aTiltXs[i], aTiltYs[i], aTwists[i]);
923 event.mTouches.AppendElement(t);
926 nsEventStatus status = nsEventStatus_eIgnore;
927 if (aToWindow) {
928 RefPtr<PresShell> presShell;
929 nsView* view = nsContentUtils::GetViewToDispatchEvent(
930 presContext, getter_AddRefs(presShell));
931 if (!presShell || !view) {
932 return NS_ERROR_FAILURE;
934 *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
935 return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
938 if (StaticPrefs::test_events_async_enabled() &&
939 StaticPrefs::test_events_async_touch_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 nsCOMPtr<Document> doc = GetDocument();
2811 if (doc) {
2812 PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker();
2813 if (tracker) {
2814 tracker->TriggerPendingAnimationsNow();
2818 nsPresContext* presContext = GetPresContext();
2819 if (presContext) {
2820 RefPtr<nsRefreshDriver> driver = presContext->RefreshDriver();
2821 driver->AdvanceTimeAndRefresh(aMilliseconds);
2823 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
2824 wrbc->SendSetTestSampleTime(driver->MostRecentRefresh());
2828 return NS_OK;
2831 NS_IMETHODIMP
2832 nsDOMWindowUtils::GetLastTransactionId(uint64_t* aLastTransactionId) {
2833 nsCOMPtr<nsIDocShell> docShell = GetDocShell();
2834 if (!docShell) {
2835 return NS_ERROR_UNEXPECTED;
2838 nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
2839 docShell->GetInProcessRootTreeItem(getter_AddRefs(rootTreeItem));
2840 docShell = do_QueryInterface(rootTreeItem);
2841 if (!docShell) {
2842 return NS_ERROR_UNEXPECTED;
2845 nsPresContext* presContext = docShell->GetPresContext();
2846 if (!presContext) {
2847 return NS_ERROR_UNEXPECTED;
2850 nsRefreshDriver* driver = presContext->RefreshDriver();
2851 *aLastTransactionId = uint64_t(driver->LastTransactionId());
2852 return NS_OK;
2855 NS_IMETHODIMP
2856 nsDOMWindowUtils::RestoreNormalRefresh() {
2857 // Kick the compositor out of test mode before the refresh driver, so that
2858 // the refresh driver doesn't send an update that gets ignored by the
2859 // compositor.
2860 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
2861 wrbc->SendLeaveTestMode();
2864 if (nsPresContext* pc = GetPresContext()) {
2865 nsRefreshDriver* driver = pc->RefreshDriver();
2866 driver->RestoreNormalRefresh();
2869 return NS_OK;
2872 NS_IMETHODIMP
2873 nsDOMWindowUtils::GetIsTestControllingRefreshes(bool* aResult) {
2874 nsPresContext* pc = GetPresContext();
2875 *aResult =
2876 pc ? pc->RefreshDriver()->IsTestControllingRefreshesEnabled() : false;
2878 return NS_OK;
2881 NS_IMETHODIMP
2882 nsDOMWindowUtils::GetAsyncPanZoomEnabled(bool* aResult) {
2883 nsIWidget* widget = GetWidget();
2884 if (widget) {
2885 *aResult = widget->AsyncPanZoomEnabled();
2886 } else {
2887 *aResult = gfxPlatform::AsyncPanZoomEnabled();
2889 return NS_OK;
2892 NS_IMETHODIMP
2893 nsDOMWindowUtils::SetAsyncScrollOffset(Element* aElement, float aX, float aY) {
2894 if (!aElement) {
2895 return NS_ERROR_INVALID_ARG;
2897 ScrollableLayerGuid::ViewID viewId;
2898 if (!nsLayoutUtils::FindIDFor(aElement, &viewId)) {
2899 return NS_ERROR_UNEXPECTED;
2901 nsIWidget* widget = GetWidget();
2902 if (!widget) {
2903 return NS_ERROR_FAILURE;
2905 WindowRenderer* renderer = widget->GetWindowRenderer();
2906 if (!renderer) {
2907 return NS_ERROR_FAILURE;
2909 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
2910 WebRenderBridgeChild* wrbc = wr->WrBridge();
2911 if (!wrbc) {
2912 return NS_ERROR_UNEXPECTED;
2914 wrbc->SendSetAsyncScrollOffset(viewId, aX, aY);
2915 return NS_OK;
2917 return NS_ERROR_UNEXPECTED;
2920 NS_IMETHODIMP
2921 nsDOMWindowUtils::SetAsyncZoom(Element* aRootElement, float aValue) {
2922 if (!aRootElement) {
2923 return NS_ERROR_INVALID_ARG;
2925 ScrollableLayerGuid::ViewID viewId;
2926 if (!nsLayoutUtils::FindIDFor(aRootElement, &viewId)) {
2927 return NS_ERROR_UNEXPECTED;
2929 nsIWidget* widget = GetWidget();
2930 if (!widget) {
2931 return NS_ERROR_FAILURE;
2933 WindowRenderer* renderer = widget->GetWindowRenderer();
2934 if (!renderer) {
2935 return NS_ERROR_FAILURE;
2937 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
2938 WebRenderBridgeChild* wrbc = wr->WrBridge();
2939 if (!wrbc) {
2940 return NS_ERROR_UNEXPECTED;
2942 wrbc->SendSetAsyncZoom(viewId, aValue);
2943 return NS_OK;
2945 return NS_ERROR_UNEXPECTED;
2948 NS_IMETHODIMP
2949 nsDOMWindowUtils::FlushApzRepaints(bool* aOutResult) {
2950 nsIWidget* widget = GetWidget();
2951 if (!widget) {
2952 *aOutResult = false;
2953 return NS_OK;
2955 // If APZ is not enabled, this function is a no-op.
2956 if (!widget->AsyncPanZoomEnabled()) {
2957 *aOutResult = false;
2958 return NS_OK;
2960 WindowRenderer* renderer = widget->GetWindowRenderer();
2961 if (!renderer) {
2962 *aOutResult = false;
2963 return NS_OK;
2965 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
2966 WebRenderBridgeChild* wrbc = wr->WrBridge();
2967 if (!wrbc) {
2968 return NS_ERROR_UNEXPECTED;
2970 wrbc->SendFlushApzRepaints();
2971 *aOutResult = true;
2972 return NS_OK;
2974 *aOutResult = false;
2975 return NS_OK;
2978 NS_IMETHODIMP
2979 nsDOMWindowUtils::DisableApzForElement(Element* aElement) {
2980 aElement->SetProperty(nsGkAtoms::apzDisabled, reinterpret_cast<void*>(true));
2981 nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aElement);
2982 if (!sf) {
2983 return NS_OK;
2985 nsIFrame* frame = do_QueryFrame(sf);
2986 if (!frame) {
2987 return NS_OK;
2989 frame->SchedulePaint();
2990 return NS_OK;
2993 static nsTArray<nsIScrollableFrame*> CollectScrollableAncestors(
2994 nsIFrame* aStart) {
2995 nsTArray<nsIScrollableFrame*> result;
2996 nsIFrame* frame = aStart;
2997 while (frame) {
2998 frame = nsLayoutUtils::GetCrossDocParentFrame(frame);
2999 if (!frame) {
3000 break;
3002 nsIScrollableFrame* scrollAncestor =
3003 nsLayoutUtils::GetAsyncScrollableAncestorFrame(frame);
3004 if (!scrollAncestor) {
3005 break;
3007 result.AppendElement(scrollAncestor);
3008 frame = do_QueryFrame(scrollAncestor);
3010 return result;
3013 NS_IMETHODIMP
3014 nsDOMWindowUtils::ZoomToFocusedInput() {
3015 if (!Preferences::GetBool("apz.zoom-to-focused-input.enabled")) {
3016 return NS_OK;
3019 nsIWidget* widget = GetWidget();
3020 if (!widget) {
3021 return NS_OK;
3024 // If APZ is not enabled, this function is a no-op.
3026 // FIXME(emilio): This is not quite true anymore now that we also
3027 // ScrollIntoView() too...
3028 if (!widget->AsyncPanZoomEnabled()) {
3029 return NS_OK;
3032 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3033 if (!fm) {
3034 return NS_OK;
3037 RefPtr<Element> element = fm->GetFocusedElement();
3038 if (!element) {
3039 return NS_OK;
3042 RefPtr<PresShell> presShell =
3043 APZCCallbackHelper::GetRootContentDocumentPresShellForContent(element);
3044 if (!presShell) {
3045 return NS_OK;
3048 bool shouldSkip = [&] {
3049 nsIFrame* frame = element->GetPrimaryFrame();
3050 if (!frame) {
3051 return true;
3054 // Skip zooming to focused inputs in fixed subtrees, as we'd scroll to the
3055 // top unnecessarily, see bug 1627734.
3057 // We could try to teach apz to zoom to a rect only without panning, or
3058 // maybe we could give it a rect offsetted by the root scroll position, if
3059 // we wanted to do this.
3060 for (; frame; frame = nsLayoutUtils::GetCrossDocParentFrame(frame)) {
3061 if (frame->PresShell() == presShell) {
3062 // Note that we only do this if the frame belongs to `presShell` (that
3063 // is, we still zoom in fixed elements in subdocuments, as they're not
3064 // fixed to the root content document).
3065 return nsLayoutUtils::IsInPositionFixedSubtree(frame);
3067 frame = frame->PresShell()->GetRootFrame();
3070 return false;
3071 }();
3073 // The content may be inside a scrollable subframe inside a non-scrollable
3074 // root content document. In this scenario, we want to ensure that the
3075 // main-thread side knows to scroll the content into view before we get
3076 // the bounding content rect and ask APZ to adjust the visual viewport.
3077 presShell->ScrollContentIntoView(
3078 element, ScrollAxis(WhereToScroll::Nearest, WhenToScroll::IfNotVisible),
3079 ScrollAxis(WhereToScroll::Nearest, WhenToScroll::IfNotVisible),
3080 ScrollFlags::ScrollOverflowHidden);
3082 if (shouldSkip) {
3083 return NS_OK;
3086 RefPtr<Document> document = presShell->GetDocument();
3087 if (!document) {
3088 return NS_OK;
3091 uint32_t presShellId;
3092 ScrollableLayerGuid::ViewID viewId;
3093 if (!APZCCallbackHelper::GetOrCreateScrollIdentifiers(
3094 document->GetDocumentElement(), &presShellId, &viewId)) {
3095 return NS_OK;
3098 TouchBehaviorFlags tbf =
3099 layers::TouchActionHelper::GetAllowedTouchBehaviorForFrame(
3100 element->GetPrimaryFrame());
3102 uint32_t flags = layers::DISABLE_ZOOM_OUT | layers::ZOOM_TO_FOCUSED_INPUT;
3103 if (!Preferences::GetBool("formhelper.autozoom") ||
3104 Preferences::GetBool("formhelper.autozoom.force-disable.test-only",
3105 /* aFallback = */ false) ||
3106 !(tbf & AllowedTouchBehavior::ANIMATING_ZOOM)) {
3107 flags |= layers::PAN_INTO_VIEW_ONLY;
3108 } else {
3109 flags |= layers::ONLY_ZOOM_TO_DEFAULT_SCALE;
3112 nsIScrollableFrame* rootScrollFrame =
3113 presShell->GetRootScrollFrameAsScrollable();
3114 if (!rootScrollFrame) {
3115 return NS_OK;
3118 CSSRect bounds;
3119 if (element->IsHTMLElement(nsGkAtoms::input)) {
3120 bounds = nsLayoutUtils::GetBoundingContentRect(element, rootScrollFrame);
3121 } else {
3122 // When focused elment is content editable or <textarea> element,
3123 // focused element will have multi-line content.
3124 nsIFrame* frame = element->GetPrimaryFrame();
3125 if (frame) {
3126 RefPtr<nsCaret> caret = frame->PresShell()->GetCaret();
3127 if (caret && caret->IsVisible()) {
3128 nsRect rect;
3129 if (nsIFrame* frame = caret->GetGeometry(&rect)) {
3130 bounds = nsLayoutUtils::GetBoundingFrameRect(frame, rootScrollFrame);
3134 if (bounds.IsEmpty()) {
3135 // Fallback if no caret frame.
3136 bounds = nsLayoutUtils::GetBoundingContentRect(element, rootScrollFrame);
3140 if (bounds.IsEmpty()) {
3141 // Do not zoom on empty bounds. Bail out.
3142 return NS_OK;
3145 bool waitForRefresh = false;
3146 for (nsIScrollableFrame* scrollAncestor :
3147 CollectScrollableAncestors(element->GetPrimaryFrame())) {
3148 if (scrollAncestor->HasScrollUpdates()) {
3149 waitForRefresh = true;
3150 break;
3153 if (waitForRefresh) {
3154 waitForRefresh = false;
3155 if (nsPresContext* presContext = presShell->GetPresContext()) {
3156 waitForRefresh = true;
3157 presContext->RegisterManagedPostRefreshObserver(
3158 new ManagedPostRefreshObserver(
3159 presContext, [widget = RefPtr<nsIWidget>(widget), presShellId,
3160 viewId, bounds, flags](bool aWasCanceled) {
3161 if (!aWasCanceled) {
3162 widget->ZoomToRect(presShellId, viewId, bounds, flags);
3164 return ManagedPostRefreshObserver::Unregister::Yes;
3165 }));
3168 if (!waitForRefresh) {
3169 widget->ZoomToRect(presShellId, viewId, bounds, flags);
3172 return NS_OK;
3175 NS_IMETHODIMP
3176 nsDOMWindowUtils::ComputeAnimationDistance(Element* aElement,
3177 const nsAString& aProperty,
3178 const nsAString& aValue1,
3179 const nsAString& aValue2,
3180 double* aResult) {
3181 NS_ENSURE_ARG_POINTER(aElement);
3183 nsCSSPropertyID property =
3184 nsCSSProps::LookupProperty(NS_ConvertUTF16toUTF8(aProperty));
3185 if (property == eCSSProperty_UNKNOWN || nsCSSProps::IsShorthand(property)) {
3186 return NS_ERROR_ILLEGAL_VALUE;
3189 AnimationValue v1 = AnimationValue::FromString(
3190 property, NS_ConvertUTF16toUTF8(aValue1), aElement);
3191 AnimationValue v2 = AnimationValue::FromString(
3192 property, NS_ConvertUTF16toUTF8(aValue2), aElement);
3193 if (v1.IsNull() || v2.IsNull()) {
3194 return NS_ERROR_ILLEGAL_VALUE;
3197 *aResult = v1.ComputeDistance(property, v2);
3198 return NS_OK;
3201 NS_IMETHODIMP
3202 nsDOMWindowUtils::GetUnanimatedComputedStyle(Element* aElement,
3203 const nsAString& aPseudoElement,
3204 const nsAString& aProperty,
3205 int32_t aFlushType,
3206 nsAString& aResult) {
3207 if (!aElement) {
3208 return NS_ERROR_INVALID_ARG;
3211 nsCSSPropertyID propertyID =
3212 nsCSSProps::LookupProperty(NS_ConvertUTF16toUTF8(aProperty));
3213 if (propertyID == eCSSProperty_UNKNOWN ||
3214 nsCSSProps::IsShorthand(propertyID)) {
3215 return NS_ERROR_INVALID_ARG;
3218 switch (aFlushType) {
3219 case FLUSH_NONE:
3220 break;
3221 case FLUSH_STYLE: {
3222 if (Document* doc = aElement->GetComposedDoc()) {
3223 doc->FlushPendingNotifications(FlushType::Style);
3225 break;
3227 default:
3228 return NS_ERROR_INVALID_ARG;
3231 RefPtr<PresShell> presShell = GetPresShell();
3232 if (!presShell) {
3233 return NS_ERROR_FAILURE;
3236 Maybe<PseudoStyleType> pseudo =
3237 nsCSSPseudoElements::GetPseudoType(aPseudoElement);
3238 if (!pseudo) {
3239 return NS_ERROR_FAILURE;
3241 RefPtr<const ComputedStyle> computedStyle =
3242 nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(aElement, *pseudo);
3243 if (!computedStyle) {
3244 return NS_ERROR_FAILURE;
3247 RefPtr<StyleAnimationValue> value =
3248 Servo_ComputedValues_ExtractAnimationValue(computedStyle, propertyID)
3249 .Consume();
3250 if (!value) {
3251 return NS_ERROR_FAILURE;
3253 if (!aElement->GetComposedDoc()) {
3254 return NS_ERROR_FAILURE;
3256 nsAutoCString result;
3257 Servo_AnimationValue_Serialize(value, propertyID,
3258 presShell->StyleSet()->RawData(), &result);
3259 CopyUTF8toUTF16(result, aResult);
3260 return NS_OK;
3263 NS_IMETHODIMP
3264 nsDOMWindowUtils::GetDisplayDPI(float* aDPI) {
3265 nsCOMPtr<nsIWidget> widget = GetWidget();
3266 if (!widget) return NS_ERROR_FAILURE;
3268 *aDPI = widget->GetDPI();
3270 return NS_OK;
3273 NS_IMETHODIMP
3274 nsDOMWindowUtils::CheckAndClearPaintedState(Element* aElement, bool* aResult) {
3275 if (!aElement) {
3276 return NS_ERROR_INVALID_ARG;
3279 nsIFrame* frame = aElement->GetPrimaryFrame();
3281 if (!frame) {
3282 *aResult = false;
3283 return NS_OK;
3286 // Get the outermost frame for the content node, so that we can test
3287 // canvasframe invalidations by observing the documentElement.
3288 for (;;) {
3289 nsIFrame* parentFrame = frame->GetParent();
3290 if (parentFrame && parentFrame->GetContent() == aElement) {
3291 frame = parentFrame;
3292 } else {
3293 break;
3297 while (frame) {
3298 if (!frame->CheckAndClearPaintedState()) {
3299 *aResult = false;
3300 return NS_OK;
3302 frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame);
3304 *aResult = true;
3305 return NS_OK;
3308 NS_IMETHODIMP
3309 nsDOMWindowUtils::CheckAndClearDisplayListState(Element* aElement,
3310 bool* aResult) {
3311 if (!aElement) {
3312 return NS_ERROR_INVALID_ARG;
3315 nsIFrame* frame = aElement->GetPrimaryFrame();
3317 if (!frame) {
3318 *aResult = false;
3319 return NS_OK;
3322 // Get the outermost frame for the content node, so that we can test
3323 // canvasframe invalidations by observing the documentElement.
3324 for (;;) {
3325 nsIFrame* parentFrame = frame->GetParent();
3326 if (parentFrame && parentFrame->GetContent() == aElement) {
3327 frame = parentFrame;
3328 } else {
3329 break;
3333 while (frame) {
3334 if (!frame->CheckAndClearDisplayListState()) {
3335 *aResult = false;
3336 return NS_OK;
3338 frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame);
3340 *aResult = true;
3341 return NS_OK;
3344 NS_IMETHODIMP
3345 nsDOMWindowUtils::IsPartOfOpaqueLayer(Element* aElement, bool* aResult) {
3346 if (!aElement) {
3347 return NS_ERROR_INVALID_ARG;
3350 nsIFrame* frame = aElement->GetPrimaryFrame();
3351 if (!frame) {
3352 return NS_ERROR_FAILURE;
3355 return NS_ERROR_FAILURE;
3358 NS_IMETHODIMP
3359 nsDOMWindowUtils::NumberOfAssignedPaintedLayers(
3360 const nsTArray<RefPtr<Element>>& aElements, uint32_t* aResult) {
3361 return NS_ERROR_FAILURE;
3364 NS_IMETHODIMP
3365 nsDOMWindowUtils::EnableDialogs() {
3366 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3367 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3369 nsGlobalWindowOuter::Cast(window)->EnableDialogs();
3370 return NS_OK;
3373 NS_IMETHODIMP
3374 nsDOMWindowUtils::DisableDialogs() {
3375 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3376 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3378 nsGlobalWindowOuter::Cast(window)->DisableDialogs();
3379 return NS_OK;
3382 NS_IMETHODIMP
3383 nsDOMWindowUtils::AreDialogsEnabled(bool* aResult) {
3384 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3385 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3387 *aResult = nsGlobalWindowOuter::Cast(window)->AreDialogsEnabled();
3388 return NS_OK;
3391 NS_IMETHODIMP
3392 nsDOMWindowUtils::ResetDialogAbuseState() {
3393 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3394 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3396 nsGlobalWindowOuter::Cast(window)
3397 ->GetBrowsingContextGroup()
3398 ->ResetDialogAbuseState();
3399 return NS_OK;
3402 NS_IMETHODIMP
3403 nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx,
3404 int64_t* _retval) {
3405 if (aFile.isPrimitive()) {
3406 *_retval = -1;
3407 return NS_OK;
3410 JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull());
3412 Blob* blob = nullptr;
3413 if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
3414 *_retval = blob->GetFileId();
3415 return NS_OK;
3418 *_retval = -1;
3419 return NS_OK;
3422 NS_IMETHODIMP
3423 nsDOMWindowUtils::GetFilePath(JS::Handle<JS::Value> aFile, JSContext* aCx,
3424 nsAString& _retval) {
3425 if (aFile.isPrimitive()) {
3426 _retval.Truncate();
3427 return NS_OK;
3430 JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull());
3432 File* file = nullptr;
3433 if (NS_SUCCEEDED(UNWRAP_OBJECT(File, &obj, file))) {
3434 nsString filePath;
3435 ErrorResult rv;
3436 file->GetMozFullPathInternal(filePath, rv);
3437 if (NS_WARN_IF(rv.Failed())) {
3438 return rv.StealNSResult();
3441 _retval = filePath;
3442 return NS_OK;
3445 _retval.Truncate();
3446 return NS_OK;
3449 NS_IMETHODIMP
3450 nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId,
3451 int32_t* aRefCnt, int32_t* aDBRefCnt,
3452 bool* aResult) {
3453 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3454 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3456 quota::PrincipalMetadata principalMetadata;
3457 MOZ_TRY_VAR(principalMetadata,
3458 quota::QuotaManager::GetInfoFromWindow(window));
3460 RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
3461 if (mgr) {
3462 nsresult rv = mgr->BlockAndGetFileReferences(
3463 principalMetadata.mIsPrivate ? quota::PERSISTENCE_TYPE_PRIVATE
3464 : quota::PERSISTENCE_TYPE_DEFAULT,
3465 principalMetadata.mOrigin, aDatabaseName, aId, aRefCnt, aDBRefCnt,
3466 aResult);
3468 NS_ENSURE_SUCCESS(rv, rv);
3469 } else {
3470 *aRefCnt = *aDBRefCnt = -1;
3471 *aResult = false;
3474 return NS_OK;
3477 NS_IMETHODIMP
3478 nsDOMWindowUtils::FlushPendingFileDeletions() {
3479 RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
3480 if (mgr) {
3481 nsresult rv = mgr->FlushPendingFileDeletions();
3482 if (NS_WARN_IF(NS_FAILED(rv))) {
3483 return rv;
3487 return NS_OK;
3490 NS_IMETHODIMP
3491 nsDOMWindowUtils::StartPCCountProfiling(JSContext* cx) {
3492 JS::StartPCCountProfiling(cx);
3493 return NS_OK;
3496 NS_IMETHODIMP
3497 nsDOMWindowUtils::StopPCCountProfiling(JSContext* cx) {
3498 JS::StopPCCountProfiling(cx);
3499 return NS_OK;
3502 NS_IMETHODIMP
3503 nsDOMWindowUtils::PurgePCCounts(JSContext* cx) {
3504 JS::PurgePCCounts(cx);
3505 return NS_OK;
3508 NS_IMETHODIMP
3509 nsDOMWindowUtils::GetPCCountScriptCount(JSContext* cx, int32_t* result) {
3510 *result = JS::GetPCCountScriptCount(cx);
3511 return NS_OK;
3514 NS_IMETHODIMP
3515 nsDOMWindowUtils::GetPCCountScriptSummary(int32_t script, JSContext* cx,
3516 nsAString& result) {
3517 JSString* text = JS::GetPCCountScriptSummary(cx, script);
3518 if (!text) return NS_ERROR_FAILURE;
3520 if (!AssignJSString(cx, result, text)) return NS_ERROR_FAILURE;
3522 return NS_OK;
3525 NS_IMETHODIMP
3526 nsDOMWindowUtils::GetPCCountScriptContents(int32_t script, JSContext* cx,
3527 nsAString& result) {
3528 JSString* text = JS::GetPCCountScriptContents(cx, script);
3529 if (!text) return NS_ERROR_FAILURE;
3531 if (!AssignJSString(cx, result, text)) return NS_ERROR_FAILURE;
3533 return NS_OK;
3536 NS_IMETHODIMP
3537 nsDOMWindowUtils::GetPaintingSuppressed(bool* aPaintingSuppressed) {
3538 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3539 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
3540 nsIDocShell* docShell = window->GetDocShell();
3541 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
3543 PresShell* presShell = docShell->GetPresShell();
3544 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
3546 *aPaintingSuppressed = presShell->IsPaintingSuppressed();
3547 return NS_OK;
3550 NS_IMETHODIMP
3551 nsDOMWindowUtils::SetVisualViewportSize(float aWidth, float aHeight) {
3552 if (!(aWidth >= 0.0 && aHeight >= 0.0)) {
3553 return NS_ERROR_ILLEGAL_VALUE;
3556 PresShell* presShell = GetPresShell();
3557 if (!presShell) {
3558 return NS_ERROR_FAILURE;
3561 presShell->SetVisualViewportSize(nsPresContext::CSSPixelsToAppUnits(aWidth),
3562 nsPresContext::CSSPixelsToAppUnits(aHeight));
3564 return NS_OK;
3567 nsresult nsDOMWindowUtils::RemoteFrameFullscreenChanged(
3568 Element* aFrameElement) {
3569 nsCOMPtr<Document> doc = GetDocument();
3570 NS_ENSURE_STATE(doc);
3572 doc->RemoteFrameFullscreenChanged(aFrameElement);
3573 return NS_OK;
3576 nsresult nsDOMWindowUtils::RemoteFrameFullscreenReverted() {
3577 nsCOMPtr<Document> doc = GetDocument();
3578 NS_ENSURE_STATE(doc);
3580 doc->RemoteFrameFullscreenReverted();
3581 return NS_OK;
3584 static void PrepareForFullscreenChange(nsIDocShell* aDocShell,
3585 const nsSize& aSize,
3586 nsSize* aOldSize = nullptr) {
3587 if (!aDocShell) {
3588 return;
3590 PresShell* presShell = aDocShell->GetPresShell();
3591 if (!presShell) {
3592 return;
3594 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
3595 rd->SetIsResizeSuppressed();
3596 // Since we are suppressing the resize reflow which would originally
3597 // be triggered by view manager, we need to ensure that the refresh
3598 // driver actually schedules a flush, otherwise it may get stuck.
3599 rd->ScheduleViewManagerFlush();
3601 if (!aSize.IsEmpty()) {
3602 nsCOMPtr<nsIContentViewer> cv;
3603 aDocShell->GetContentViewer(getter_AddRefs(cv));
3604 if (cv) {
3605 nsIntRect cvBounds;
3606 cv->GetBounds(cvBounds);
3607 nscoord auPerDev = presShell->GetPresContext()->AppUnitsPerDevPixel();
3608 if (aOldSize) {
3609 *aOldSize = LayoutDeviceIntSize::ToAppUnits(
3610 LayoutDeviceIntSize::FromUnknownSize(cvBounds.Size()), auPerDev);
3612 LayoutDeviceIntSize newSize =
3613 LayoutDeviceIntSize::FromAppUnitsRounded(aSize, auPerDev);
3615 cvBounds.SizeTo(newSize.width, newSize.height);
3616 cv->SetBounds(cvBounds);
3621 NS_IMETHODIMP
3622 nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal) {
3623 PROFILER_MARKER_UNTYPED("Enter fullscreen", DOM);
3624 nsCOMPtr<Document> doc = GetDocument();
3625 NS_ENSURE_STATE(doc);
3627 // Notify the pres shell that we are starting fullscreen change, and
3628 // set the window dimensions in advance. Since the resize message
3629 // comes after the fullscreen change call, doing so could avoid an
3630 // extra resize reflow after this point.
3631 nsRect screenRect;
3632 if (nsPresContext* presContext = GetPresContext()) {
3633 presContext->DeviceContext()->GetRect(screenRect);
3635 nsSize oldSize;
3636 PrepareForFullscreenChange(GetDocShell(), screenRect.Size(), &oldSize);
3637 OldWindowSize::Set(mWindow, oldSize);
3639 *aRetVal = Document::HandlePendingFullscreenRequests(doc);
3640 return NS_OK;
3643 nsresult nsDOMWindowUtils::ExitFullscreen(bool aDontRestoreViewSize) {
3644 PROFILER_MARKER_UNTYPED("Exit fullscreen", DOM);
3645 nsCOMPtr<Document> doc = GetDocument();
3646 NS_ENSURE_STATE(doc);
3648 // Although we would not use the old size if we have already exited
3649 // fullscreen, we still want to cleanup in case we haven't.
3650 nsSize oldSize = OldWindowSize::GetAndRemove(mWindow);
3651 if (!doc->GetFullscreenElement()) {
3652 return NS_OK;
3655 // Notify the pres shell that we are starting fullscreen change, and
3656 // set the window dimensions in advance. Since the resize message
3657 // comes after the fullscreen change call, doing so could avoid an
3658 // extra resize reflow after this point.
3659 PrepareForFullscreenChange(GetDocShell(),
3660 aDontRestoreViewSize ? nsSize() : oldSize);
3661 Document::ExitFullscreenInDocTree(doc);
3662 return NS_OK;
3665 NS_IMETHODIMP
3666 nsDOMWindowUtils::SelectAtPoint(float aX, float aY, uint32_t aSelectBehavior,
3667 bool* _retval) {
3668 *_retval = false;
3670 nsSelectionAmount amount;
3671 switch (aSelectBehavior) {
3672 case nsIDOMWindowUtils::SELECT_CHARACTER:
3673 amount = eSelectCharacter;
3674 break;
3675 case nsIDOMWindowUtils::SELECT_CLUSTER:
3676 amount = eSelectCluster;
3677 break;
3678 case nsIDOMWindowUtils::SELECT_WORD:
3679 amount = eSelectWord;
3680 break;
3681 case nsIDOMWindowUtils::SELECT_LINE:
3682 amount = eSelectLine;
3683 break;
3684 case nsIDOMWindowUtils::SELECT_BEGINLINE:
3685 amount = eSelectBeginLine;
3686 break;
3687 case nsIDOMWindowUtils::SELECT_ENDLINE:
3688 amount = eSelectEndLine;
3689 break;
3690 case nsIDOMWindowUtils::SELECT_PARAGRAPH:
3691 amount = eSelectParagraph;
3692 break;
3693 case nsIDOMWindowUtils::SELECT_WORDNOSPACE:
3694 amount = eSelectWordNoSpace;
3695 break;
3696 default:
3697 return NS_ERROR_INVALID_ARG;
3700 PresShell* presShell = GetPresShell();
3701 if (!presShell) {
3702 return NS_ERROR_UNEXPECTED;
3705 // The root frame for this content window
3706 nsIFrame* rootFrame = presShell->GetRootFrame();
3707 if (!rootFrame) {
3708 return NS_ERROR_UNEXPECTED;
3711 // Get the target frame at the client coordinates passed to us
3712 nsPoint offset;
3713 nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
3714 LayoutDeviceIntPoint pt =
3715 nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext());
3716 nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(
3717 widget, pt, RelativeTo{rootFrame});
3718 nsIFrame* targetFrame =
3719 nsLayoutUtils::GetFrameForPoint(RelativeTo{rootFrame}, ptInRoot);
3720 // This can happen if the page hasn't loaded yet or if the point
3721 // is outside the frame.
3722 if (!targetFrame) {
3723 return NS_ERROR_INVALID_ARG;
3726 // Convert point to coordinates relative to the target frame, which is
3727 // what targetFrame's SelectByTypeAtPoint expects.
3728 nsPoint relPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(
3729 widget, pt, RelativeTo{targetFrame});
3731 const RefPtr<nsPresContext> pinnedPresContext{GetPresContext()};
3732 nsresult rv = targetFrame->SelectByTypeAtPoint(
3733 pinnedPresContext, relPoint, amount, amount, nsIFrame::SELECT_ACCUMULATE);
3734 *_retval = !NS_FAILED(rv);
3735 return NS_OK;
3738 static Document::additionalSheetType convertSheetType(uint32_t aSheetType) {
3739 switch (aSheetType) {
3740 case nsDOMWindowUtils::AGENT_SHEET:
3741 return Document::eAgentSheet;
3742 case nsDOMWindowUtils::USER_SHEET:
3743 return Document::eUserSheet;
3744 case nsDOMWindowUtils::AUTHOR_SHEET:
3745 return Document::eAuthorSheet;
3746 default:
3747 NS_ASSERTION(false, "wrong type");
3748 // we must return something although this should never happen
3749 return Document::AdditionalSheetTypeCount;
3753 NS_IMETHODIMP
3754 nsDOMWindowUtils::LoadSheet(nsIURI* aSheetURI, uint32_t aSheetType) {
3755 NS_ENSURE_ARG_POINTER(aSheetURI);
3756 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
3757 aSheetType == AUTHOR_SHEET);
3759 nsCOMPtr<Document> doc = GetDocument();
3760 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
3762 Document::additionalSheetType type = convertSheetType(aSheetType);
3764 return doc->LoadAdditionalStyleSheet(type, aSheetURI);
3767 NS_IMETHODIMP
3768 nsDOMWindowUtils::LoadSheetUsingURIString(const nsACString& aSheetURI,
3769 uint32_t aSheetType) {
3770 nsCOMPtr<nsIURI> uri;
3771 nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI);
3772 NS_ENSURE_SUCCESS(rv, rv);
3774 return LoadSheet(uri, aSheetType);
3777 NS_IMETHODIMP
3778 nsDOMWindowUtils::AddSheet(nsIPreloadedStyleSheet* aSheet,
3779 uint32_t aSheetType) {
3780 NS_ENSURE_ARG_POINTER(aSheet);
3781 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
3782 aSheetType == AUTHOR_SHEET);
3784 nsCOMPtr<Document> doc = GetDocument();
3785 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
3787 StyleSheet* sheet = nullptr;
3788 auto* preloadedSheet = static_cast<PreloadedStyleSheet*>(aSheet);
3789 nsresult rv = preloadedSheet->GetSheet(&sheet);
3790 NS_ENSURE_SUCCESS(rv, rv);
3791 NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
3793 if (sheet->GetAssociatedDocumentOrShadowRoot()) {
3794 return NS_ERROR_INVALID_ARG;
3797 Document::additionalSheetType type = convertSheetType(aSheetType);
3798 return doc->AddAdditionalStyleSheet(type, sheet);
3801 NS_IMETHODIMP
3802 nsDOMWindowUtils::RemoveSheet(nsIURI* aSheetURI, uint32_t aSheetType) {
3803 NS_ENSURE_ARG_POINTER(aSheetURI);
3804 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
3805 aSheetType == AUTHOR_SHEET);
3807 nsCOMPtr<Document> doc = GetDocument();
3808 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
3810 Document::additionalSheetType type = convertSheetType(aSheetType);
3812 doc->RemoveAdditionalStyleSheet(type, aSheetURI);
3813 return NS_OK;
3816 NS_IMETHODIMP
3817 nsDOMWindowUtils::RemoveSheetUsingURIString(const nsACString& aSheetURI,
3818 uint32_t aSheetType) {
3819 nsCOMPtr<nsIURI> uri;
3820 nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI);
3821 NS_ENSURE_SUCCESS(rv, rv);
3823 return RemoveSheet(uri, aSheetType);
3826 NS_IMETHODIMP
3827 nsDOMWindowUtils::GetIsHandlingUserInput(bool* aHandlingUserInput) {
3828 *aHandlingUserInput = UserActivation::IsHandlingUserInput();
3830 return NS_OK;
3833 NS_IMETHODIMP
3834 nsDOMWindowUtils::GetMillisSinceLastUserInput(
3835 double* aMillisSinceLastUserInput) {
3836 TimeStamp lastInput = UserActivation::LatestUserInputStart();
3837 if (lastInput.IsNull()) {
3838 *aMillisSinceLastUserInput = -1.0f;
3839 return NS_OK;
3842 *aMillisSinceLastUserInput = (TimeStamp::Now() - lastInput).ToMilliseconds();
3843 return NS_OK;
3846 NS_IMETHODIMP
3847 nsDOMWindowUtils::AllowScriptsToClose() {
3848 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3849 NS_ENSURE_STATE(window);
3850 nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose();
3851 return NS_OK;
3854 NS_IMETHODIMP
3855 nsDOMWindowUtils::GetIsParentWindowMainWidgetVisible(bool* aIsVisible) {
3856 if (!XRE_IsParentProcess()) {
3857 MOZ_CRASH(
3858 "IsParentWindowMainWidgetVisible is only available in the parent "
3859 "process");
3862 // this should reflect the "is parent window visible" logic in
3863 // nsWindowWatcher::OpenWindowInternal()
3864 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
3865 NS_ENSURE_STATE(window);
3867 nsCOMPtr<nsIWidget> parentWidget;
3868 nsIDocShell* docShell = window->GetDocShell();
3869 if (docShell) {
3870 nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
3871 docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
3872 nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(parentTreeOwner));
3873 if (parentWindow) {
3874 parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
3877 if (!parentWidget) {
3878 return NS_ERROR_NOT_AVAILABLE;
3881 *aIsVisible = parentWidget->IsVisible();
3882 return NS_OK;
3885 NS_IMETHODIMP
3886 nsDOMWindowUtils::IsNodeDisabledForEvents(nsINode* aNode, bool* aRetVal) {
3887 *aRetVal = false;
3888 nsINode* node = aNode;
3889 while (node) {
3890 if (node->IsHTMLFormControlElement()) {
3891 nsGenericHTMLElement* element = nsGenericHTMLElement::FromNode(node);
3892 WidgetEvent event(true, eVoidEvent);
3893 if (element && element->IsDisabledForEvents(&event)) {
3894 *aRetVal = true;
3895 break;
3898 node = node->GetParentNode();
3901 return NS_OK;
3904 NS_IMETHODIMP
3905 nsDOMWindowUtils::DispatchEventToChromeOnly(EventTarget* aTarget, Event* aEvent,
3906 bool* aRetVal) {
3907 *aRetVal = false;
3908 NS_ENSURE_STATE(aTarget && aEvent);
3909 aEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3910 *aRetVal =
3911 aTarget->DispatchEvent(*aEvent, CallerType::System, IgnoreErrors());
3912 return NS_OK;
3915 static Result<nsIFrame*, nsresult> GetTargetFrame(
3916 const Element* aElement, const nsAString& aPseudoElement) {
3917 nsIFrame* frame = aElement->GetPrimaryFrame();
3918 if (!aPseudoElement.IsEmpty()) {
3919 if (aPseudoElement.EqualsLiteral("::before")) {
3920 frame = nsLayoutUtils::GetBeforeFrame(aElement);
3921 } else if (aPseudoElement.EqualsLiteral("::after")) {
3922 frame = nsLayoutUtils::GetAfterFrame(aElement);
3923 } else {
3924 return Err(NS_ERROR_INVALID_ARG);
3927 return frame;
3930 static OMTAValue GetOMTAValue(nsIFrame* aFrame, DisplayItemType aDisplayItemKey,
3931 WebRenderBridgeChild* aWebRenderBridgeChild) {
3932 OMTAValue value = mozilla::null_t();
3934 if (aWebRenderBridgeChild) {
3935 RefPtr<WebRenderAnimationData> animationData =
3936 GetWebRenderUserData<WebRenderAnimationData>(aFrame,
3937 (uint32_t)aDisplayItemKey);
3938 if (animationData) {
3939 aWebRenderBridgeChild->SendGetAnimationValue(
3940 animationData->GetAnimationInfo().GetCompositorAnimationsId(),
3941 &value);
3944 return value;
3947 NS_IMETHODIMP
3948 nsDOMWindowUtils::GetOMTAStyle(Element* aElement, const nsAString& aProperty,
3949 const nsAString& aPseudoElement,
3950 nsAString& aResult) {
3951 if (!aElement) {
3952 return NS_ERROR_INVALID_ARG;
3955 auto frameOrError = GetTargetFrame(aElement, aPseudoElement);
3956 if (frameOrError.isErr()) {
3957 return frameOrError.unwrapErr();
3959 nsIFrame* frame = frameOrError.unwrap();
3961 RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
3962 if (frame && nsLayoutUtils::AreAsyncAnimationsEnabled()) {
3963 if (aProperty.EqualsLiteral("opacity")) {
3964 OMTAValue value = GetOMTAValue(frame, DisplayItemType::TYPE_OPACITY,
3965 GetWebRenderBridge());
3966 if (value.type() == OMTAValue::Tfloat) {
3967 cssValue = new nsROCSSPrimitiveValue;
3968 cssValue->SetNumber(value.get_float());
3970 } else if (aProperty.EqualsLiteral("transform") ||
3971 aProperty.EqualsLiteral("translate") ||
3972 aProperty.EqualsLiteral("rotate") ||
3973 aProperty.EqualsLiteral("scale") ||
3974 aProperty.EqualsLiteral("offset-path") ||
3975 aProperty.EqualsLiteral("offset-distance") ||
3976 aProperty.EqualsLiteral("offset-rotate") ||
3977 aProperty.EqualsLiteral("offset-anchor") ||
3978 aProperty.EqualsLiteral("offset-position")) {
3979 OMTAValue value = GetOMTAValue(frame, DisplayItemType::TYPE_TRANSFORM,
3980 GetWebRenderBridge());
3981 if (value.type() == OMTAValue::TMatrix4x4) {
3982 cssValue = nsComputedDOMStyle::MatrixToCSSValue(value.get_Matrix4x4());
3984 } else if (aProperty.EqualsLiteral("background-color")) {
3985 OMTAValue value = GetOMTAValue(
3986 frame, DisplayItemType::TYPE_BACKGROUND_COLOR, GetWebRenderBridge());
3987 if (value.type() == OMTAValue::Tnscolor) {
3988 nsStyleUtil::GetSerializedColorValue(value.get_nscolor(), aResult);
3989 return NS_OK;
3994 if (cssValue) {
3995 cssValue->GetCssText(aResult);
3996 return NS_OK;
3998 aResult.Truncate();
3999 return NS_OK;
4002 NS_IMETHODIMP
4003 nsDOMWindowUtils::IsAnimationInPendingTracker(dom::Animation* aAnimation,
4004 bool* aRetVal) {
4005 MOZ_ASSERT(aRetVal);
4007 if (!aAnimation) {
4008 return NS_ERROR_INVALID_ARG;
4011 Document* doc = GetDocument();
4012 if (!doc) {
4013 *aRetVal = false;
4014 return NS_OK;
4017 PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker();
4018 if (!tracker) {
4019 *aRetVal = false;
4020 return NS_OK;
4023 *aRetVal = tracker->IsWaitingToPlay(*aAnimation) ||
4024 tracker->IsWaitingToPause(*aAnimation);
4025 return NS_OK;
4028 namespace {
4030 class HandlingUserInputHelper final : public nsIJSRAIIHelper {
4031 public:
4032 explicit HandlingUserInputHelper(bool aHandlingUserInput);
4034 NS_DECL_ISUPPORTS
4035 NS_DECL_NSIJSRAIIHELPER
4037 private:
4038 ~HandlingUserInputHelper();
4040 bool mHandlingUserInput;
4041 bool mDestructCalled = false;
4044 NS_IMPL_ISUPPORTS(HandlingUserInputHelper, nsIJSRAIIHelper)
4046 HandlingUserInputHelper::HandlingUserInputHelper(bool aHandlingUserInput)
4047 : mHandlingUserInput(aHandlingUserInput) {
4048 if (aHandlingUserInput) {
4049 UserActivation::StartHandlingUserInput(eVoidEvent);
4053 HandlingUserInputHelper::~HandlingUserInputHelper() {
4054 // We assert, but just in case, make sure we notify the ESM.
4055 MOZ_ASSERT(mDestructCalled);
4056 if (!mDestructCalled) {
4057 Destruct();
4061 NS_IMETHODIMP
4062 HandlingUserInputHelper::Destruct() {
4063 if (NS_WARN_IF(mDestructCalled)) {
4064 return NS_ERROR_FAILURE;
4067 mDestructCalled = true;
4068 if (mHandlingUserInput) {
4069 UserActivation::StopHandlingUserInput(eVoidEvent);
4072 return NS_OK;
4075 } // unnamed namespace
4077 NS_IMETHODIMP
4078 nsDOMWindowUtils::SetHandlingUserInput(bool aHandlingUserInput,
4079 nsIJSRAIIHelper** aHelper) {
4080 if (aHandlingUserInput) {
4081 if (Document* doc = GetDocument()) {
4082 doc->NotifyUserGestureActivation();
4085 auto helper = MakeRefPtr<HandlingUserInputHelper>(aHandlingUserInput);
4086 helper.forget(aHelper);
4087 return NS_OK;
4090 NS_IMETHODIMP
4091 nsDOMWindowUtils::IsKeyboardEventUserActivity(Event* aEvent, bool* aResult) {
4092 NS_ENSURE_STATE(aEvent);
4093 if (!aEvent->AsKeyboardEvent()) {
4094 return NS_ERROR_INVALID_ARG;
4097 WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
4098 NS_ENSURE_STATE(internalEvent);
4099 *aResult = EventStateManager::IsKeyboardEventUserActivity(internalEvent);
4100 return NS_OK;
4103 NS_IMETHODIMP
4104 nsDOMWindowUtils::GetContentAPZTestData(
4105 JSContext* aContext, JS::MutableHandle<JS::Value> aOutContentTestData) {
4106 if (nsIWidget* widget = GetWidget()) {
4107 WindowRenderer* renderer = widget->GetWindowRenderer();
4108 if (!renderer) {
4109 return NS_OK;
4111 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
4112 if (!wr->GetAPZTestData().ToJS(aOutContentTestData, aContext)) {
4113 return NS_ERROR_FAILURE;
4118 return NS_OK;
4121 NS_IMETHODIMP
4122 nsDOMWindowUtils::GetCompositorAPZTestData(
4123 JSContext* aContext, JS::MutableHandle<JS::Value> aOutCompositorTestData) {
4124 if (nsIWidget* widget = GetWidget()) {
4125 WindowRenderer* renderer = widget->GetWindowRenderer();
4126 if (!renderer) {
4127 return NS_OK;
4129 APZTestData compositorSideData;
4130 if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
4131 if (!wr->WrBridge()) {
4132 return NS_ERROR_UNEXPECTED;
4134 if (!wr->WrBridge()->SendGetAPZTestData(&compositorSideData)) {
4135 return NS_ERROR_FAILURE;
4138 if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) {
4139 return NS_ERROR_FAILURE;
4143 return NS_OK;
4146 NS_IMETHODIMP
4147 nsDOMWindowUtils::PostRestyleSelfEvent(Element* aElement) {
4148 if (!aElement) {
4149 return NS_ERROR_INVALID_ARG;
4152 nsLayoutUtils::PostRestyleEvent(aElement, RestyleHint::RESTYLE_SELF,
4153 nsChangeHint(0));
4154 return NS_OK;
4157 NS_IMETHODIMP
4158 nsDOMWindowUtils::SetChromeMargin(int32_t aTop, int32_t aRight, int32_t aBottom,
4159 int32_t aLeft) {
4160 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
4161 if (window) {
4162 nsCOMPtr<nsIBaseWindow> baseWindow =
4163 do_QueryInterface(window->GetDocShell());
4164 if (baseWindow) {
4165 nsCOMPtr<nsIWidget> widget;
4166 baseWindow->GetMainWidget(getter_AddRefs(widget));
4167 if (widget) {
4168 LayoutDeviceIntMargin margins(aTop, aRight, aBottom, aLeft);
4169 return widget->SetNonClientMargins(margins);
4174 return NS_OK;
4177 NS_IMETHODIMP
4178 nsDOMWindowUtils::SetResizeMargin(int32_t aResizeMargin) {
4179 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
4180 if (window) {
4181 nsCOMPtr<nsIBaseWindow> baseWindow =
4182 do_QueryInterface(window->GetDocShell());
4183 if (baseWindow) {
4184 nsCOMPtr<nsIWidget> widget;
4185 baseWindow->GetMainWidget(getter_AddRefs(widget));
4186 if (widget) {
4187 CSSToLayoutDeviceScale scaleFactor = widget->GetDefaultScale();
4188 widget->SetResizeMargin(
4189 (CSSCoord(float(aResizeMargin)) * scaleFactor).Rounded());
4194 return NS_OK;
4197 NS_IMETHODIMP
4198 nsDOMWindowUtils::GetFrameUniformityTestData(
4199 JSContext* aContext, JS::MutableHandle<JS::Value> aOutFrameUniformity) {
4200 nsIWidget* widget = GetWidget();
4201 if (!widget) {
4202 return NS_ERROR_NOT_AVAILABLE;
4205 WindowRenderer* renderer = widget->GetWindowRenderer();
4206 if (!renderer) {
4207 return NS_ERROR_NOT_AVAILABLE;
4210 FrameUniformityData outData;
4211 renderer->GetFrameUniformity(&outData);
4212 outData.ToJS(aOutFrameUniformity, aContext);
4213 return NS_OK;
4216 NS_IMETHODIMP
4217 nsDOMWindowUtils::XpconnectArgument(nsISupports* aObj) {
4218 // Do nothing.
4219 return NS_OK;
4222 NS_IMETHODIMP
4223 nsDOMWindowUtils::AskPermission(nsIContentPermissionRequest* aRequest) {
4224 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
4225 return nsContentPermissionUtils::AskPermission(
4226 aRequest, window->GetCurrentInnerWindow());
4229 NS_IMETHODIMP
4230 nsDOMWindowUtils::GetRestyleGeneration(uint64_t* aResult) {
4231 nsPresContext* presContext = GetPresContext();
4232 if (!presContext) {
4233 return NS_ERROR_NOT_AVAILABLE;
4236 *aResult = presContext->GetRestyleGeneration();
4237 return NS_OK;
4240 NS_IMETHODIMP
4241 nsDOMWindowUtils::GetFramesConstructed(uint64_t* aResult) {
4242 nsPresContext* presContext = GetPresContext();
4243 if (!presContext) {
4244 return NS_ERROR_NOT_AVAILABLE;
4247 *aResult = presContext->FramesConstructedCount();
4248 return NS_OK;
4251 NS_IMETHODIMP
4252 nsDOMWindowUtils::GetFramesReflowed(uint64_t* aResult) {
4253 nsPresContext* presContext = GetPresContext();
4254 if (!presContext) {
4255 return NS_ERROR_NOT_AVAILABLE;
4258 *aResult = presContext->FramesReflowedCount();
4259 return NS_OK;
4262 NS_IMETHODIMP
4263 nsDOMWindowUtils::GetAnimationTriggeredRestyles(uint64_t* aResult) {
4264 nsPresContext* presContext = GetPresContext();
4265 if (!presContext) {
4266 return NS_ERROR_NOT_AVAILABLE;
4269 *aResult = presContext->AnimationTriggeredRestylesCount();
4270 return NS_OK;
4273 NS_IMETHODIMP
4274 nsDOMWindowUtils::GetRefreshDriverHasPendingTick(bool* aResult) {
4275 nsPresContext* presContext = GetPresContext();
4276 if (!presContext) {
4277 return NS_ERROR_NOT_AVAILABLE;
4280 *aResult = presContext->RefreshDriver()->HasPendingTick();
4281 return NS_OK;
4284 NS_IMETHODIMP
4285 nsDOMWindowUtils::EnterChaosMode() {
4286 ChaosMode::enterChaosMode();
4287 return NS_OK;
4290 NS_IMETHODIMP
4291 nsDOMWindowUtils::LeaveChaosMode() {
4292 ChaosMode::leaveChaosMode();
4293 return NS_OK;
4296 NS_IMETHODIMP
4297 nsDOMWindowUtils::TriggerDeviceReset() {
4298 if (!XRE_IsParentProcess()) {
4299 return NS_ERROR_NOT_AVAILABLE;
4302 GPUProcessManager* pm = GPUProcessManager::Get();
4303 if (pm) {
4304 pm->SimulateDeviceReset();
4306 return NS_OK;
4309 NS_IMETHODIMP
4310 nsDOMWindowUtils::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
4311 bool* aRetVal) {
4312 PresShell* presShell = GetPresShell();
4313 if (!presShell) {
4314 return NS_ERROR_FAILURE;
4317 return presShell->HasRuleProcessorUsedByMultipleStyleSets(aSheetType,
4318 aRetVal);
4321 NS_IMETHODIMP
4322 nsDOMWindowUtils::RespectDisplayPortSuppression(bool aEnabled) {
4323 RefPtr<PresShell> presShell = GetPresShell();
4324 presShell->RespectDisplayportSuppression(aEnabled);
4325 return NS_OK;
4328 NS_IMETHODIMP
4329 nsDOMWindowUtils::ForceReflowInterrupt() {
4330 nsPresContext* pc = GetPresContext();
4331 if (!pc) {
4332 return NS_ERROR_NOT_AVAILABLE;
4334 pc->SetPendingInterruptFromTest();
4335 return NS_OK;
4338 NS_IMETHODIMP
4339 nsDOMWindowUtils::TerminateGPUProcess() {
4340 GPUProcessManager* pm = GPUProcessManager::Get();
4341 if (pm) {
4342 pm->KillProcess();
4344 return NS_OK;
4347 NS_IMETHODIMP
4348 nsDOMWindowUtils::GetGpuProcessPid(int32_t* aPid) {
4349 GPUProcessManager* pm = GPUProcessManager::Get();
4350 if (pm) {
4351 *aPid = pm->GPUProcessPid();
4352 } else {
4353 *aPid = -1;
4356 return NS_OK;
4359 struct StateTableEntry {
4360 const char* mStateString;
4361 ElementState mState;
4364 static constexpr StateTableEntry kManuallyManagedStates[] = {
4365 {"autofill", ElementState::AUTOFILL},
4366 // :-moz-autofill-preview implies :autofill.
4367 {"-moz-autofill-preview",
4368 ElementState::AUTOFILL_PREVIEW | ElementState::AUTOFILL},
4369 {nullptr, ElementState()},
4372 static_assert(!kManuallyManagedStates[ArrayLength(kManuallyManagedStates) - 1]
4373 .mStateString,
4374 "last kManuallyManagedStates entry must be a sentinel with "
4375 "mStateString == nullptr");
4377 static ElementState GetEventStateForString(const nsAString& aStateString) {
4378 for (const StateTableEntry* entry = kManuallyManagedStates;
4379 entry->mStateString; ++entry) {
4380 if (aStateString.EqualsASCII(entry->mStateString)) {
4381 return entry->mState;
4384 return ElementState();
4387 NS_IMETHODIMP
4388 nsDOMWindowUtils::AddManuallyManagedState(Element* aElement,
4389 const nsAString& aStateString) {
4390 if (!aElement) {
4391 return NS_ERROR_INVALID_ARG;
4394 ElementState state = GetEventStateForString(aStateString);
4395 if (state.IsEmpty()) {
4396 return NS_ERROR_INVALID_ARG;
4399 aElement->AddStates(state);
4400 return NS_OK;
4403 NS_IMETHODIMP
4404 nsDOMWindowUtils::RemoveManuallyManagedState(Element* aElement,
4405 const nsAString& aStateString) {
4406 if (!aElement) {
4407 return NS_ERROR_INVALID_ARG;
4410 ElementState state = GetEventStateForString(aStateString);
4411 if (state.IsEmpty()) {
4412 return NS_ERROR_INVALID_ARG;
4415 aElement->RemoveStates(state);
4416 return NS_OK;
4419 NS_IMETHODIMP
4420 nsDOMWindowUtils::GetStorageUsage(Storage* aStorage, int64_t* aRetval) {
4421 if (!aStorage) {
4422 return NS_ERROR_UNEXPECTED;
4425 *aRetval = aStorage->GetOriginQuotaUsage();
4427 return NS_OK;
4430 NS_IMETHODIMP
4431 nsDOMWindowUtils::GetDirectionFromText(const nsAString& aString,
4432 int32_t* aRetval) {
4433 Directionality dir =
4434 ::GetDirectionFromText(aString.BeginReading(), aString.Length(), nullptr);
4435 switch (dir) {
4436 case eDir_NotSet:
4437 *aRetval = nsIDOMWindowUtils::DIRECTION_NOT_SET;
4438 break;
4439 case eDir_RTL:
4440 *aRetval = nsIDOMWindowUtils::DIRECTION_RTL;
4441 break;
4442 case eDir_LTR:
4443 *aRetval = nsIDOMWindowUtils::DIRECTION_LTR;
4444 break;
4445 case eDir_Auto:
4446 MOZ_ASSERT_UNREACHABLE(
4447 "GetDirectionFromText should never return this value");
4448 return NS_ERROR_FAILURE;
4450 return NS_OK;
4453 NS_IMETHODIMP
4454 nsDOMWindowUtils::EnsureDirtyRootFrame() {
4455 Document* doc = GetDocument();
4456 PresShell* presShell = doc ? doc->GetPresShell() : nullptr;
4458 if (!presShell) {
4459 return NS_ERROR_FAILURE;
4462 nsIFrame* frame = presShell->GetRootFrame();
4463 if (!frame) {
4464 return NS_ERROR_FAILURE;
4467 presShell->FrameNeedsReflow(
4468 frame, IntrinsicDirty::FrameAncestorsAndDescendants, NS_FRAME_IS_DIRTY);
4469 return NS_OK;
4472 NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
4473 NS_INTERFACE_MAP_ENTRY(nsISupports)
4474 NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)
4475 NS_INTERFACE_MAP_END
4477 NS_IMPL_ADDREF(nsTranslationNodeList)
4478 NS_IMPL_RELEASE(nsTranslationNodeList)
4480 NS_IMETHODIMP
4481 nsTranslationNodeList::Item(uint32_t aIndex, nsINode** aRetVal) {
4482 NS_ENSURE_ARG_POINTER(aRetVal);
4483 NS_IF_ADDREF(*aRetVal = mNodes.SafeElementAt(aIndex));
4484 return NS_OK;
4487 NS_IMETHODIMP
4488 nsTranslationNodeList::IsTranslationRootAtIndex(uint32_t aIndex,
4489 bool* aRetVal) {
4490 NS_ENSURE_ARG_POINTER(aRetVal);
4491 if (aIndex >= mLength) {
4492 *aRetVal = false;
4493 return NS_OK;
4496 *aRetVal = mNodeIsRoot.ElementAt(aIndex);
4497 return NS_OK;
4500 NS_IMETHODIMP
4501 nsTranslationNodeList::GetLength(uint32_t* aRetVal) {
4502 NS_ENSURE_ARG_POINTER(aRetVal);
4503 *aRetVal = mLength;
4504 return NS_OK;
4507 NS_IMETHODIMP
4508 nsDOMWindowUtils::WrCapture() {
4509 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
4510 wrbc->Capture();
4512 return NS_OK;
4515 NS_IMETHODIMP
4516 nsDOMWindowUtils::WrStartCaptureSequence(const nsACString& aPath,
4517 uint32_t aFlags) {
4518 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
4519 wrbc->StartCaptureSequence(nsCString(aPath), aFlags);
4521 return NS_OK;
4524 NS_IMETHODIMP
4525 nsDOMWindowUtils::WrStopCaptureSequence() {
4526 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
4527 wrbc->StopCaptureSequence();
4529 return NS_OK;
4532 NS_IMETHODIMP
4533 nsDOMWindowUtils::SetCompositionRecording(bool aValue, Promise** aOutPromise) {
4534 return aValue ? StartCompositionRecording(aOutPromise)
4535 : StopCompositionRecording(true, aOutPromise);
4538 NS_IMETHODIMP
4539 nsDOMWindowUtils::StartCompositionRecording(Promise** aOutPromise) {
4540 NS_ENSURE_ARG(aOutPromise);
4541 *aOutPromise = nullptr;
4543 nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow);
4544 NS_ENSURE_STATE(outer);
4545 nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
4546 NS_ENSURE_STATE(inner);
4548 ErrorResult err;
4549 RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err);
4550 if (NS_WARN_IF(err.Failed())) {
4551 return err.StealNSResult();
4554 CompositorBridgeChild* cbc = GetCompositorBridge();
4555 if (NS_WARN_IF(!cbc)) {
4556 promise->MaybeReject(NS_ERROR_UNEXPECTED);
4557 } else {
4558 cbc->SendBeginRecording(TimeStamp::Now())
4559 ->Then(
4560 GetCurrentSerialEventTarget(), __func__,
4561 [promise](const bool& aSuccess) {
4562 if (aSuccess) {
4563 promise->MaybeResolve(true);
4564 } else {
4565 promise->MaybeRejectWithInvalidStateError(
4566 "The composition recorder is already running.");
4569 [promise](const mozilla::ipc::ResponseRejectReason&) {
4570 promise->MaybeRejectWithInvalidStateError(
4571 "Could not start the composition recorder.");
4575 promise.forget(aOutPromise);
4576 return NS_OK;
4579 static bool WriteRecordingToDisk(const FrameRecording& aRecording,
4580 double aUnixStartMS) {
4581 // The directory name contains the unix timestamp for when recording started,
4582 // because we want the consumer of these files to be able to compute an
4583 // absolute timestamp of each screenshot. That allows them to align
4584 // screenshots with timed data from other sources, such as Gecko profiler
4585 // information. The time of each screenshot is part of the screenshot's
4586 // filename, expressed as milliseconds from the recording start.
4587 std::stringstream recordingDirectory;
4588 recordingDirectory << gfxVars::LayersWindowRecordingPath()
4589 << "windowrecording-" << int64_t(aUnixStartMS);
4591 #ifdef XP_WIN
4592 _mkdir(recordingDirectory.str().c_str());
4593 #else
4594 mkdir(recordingDirectory.str().c_str(), 0777);
4595 #endif
4597 auto byteSpan = aRecording.bytes().AsSpan();
4599 uint32_t i = 1;
4601 for (const auto& frame : aRecording.frames()) {
4602 const uint32_t frameBufferLength = frame.length();
4603 if (frameBufferLength > byteSpan.Length()) {
4604 return false;
4607 const auto frameSpan = byteSpan.To(frameBufferLength);
4608 byteSpan = byteSpan.From(frameBufferLength);
4610 const double frameTimeMS =
4611 (frame.timeOffset() - aRecording.startTime()).ToMilliseconds();
4613 std::stringstream filename;
4614 filename << recordingDirectory.str() << "/frame-" << i << "-"
4615 << uint32_t(frameTimeMS) << ".png";
4617 FILE* file = fopen(filename.str().c_str(), "wb");
4618 if (!file) {
4619 return false;
4622 const size_t bytesWritten =
4623 fwrite(frameSpan.Elements(), sizeof(uint8_t), frameSpan.Length(), file);
4625 fclose(file);
4627 if (bytesWritten < frameSpan.Length()) {
4628 return false;
4631 ++i;
4634 return byteSpan.Length() == 0;
4637 static Maybe<DOMCollectedFrames> ConvertCompositionRecordingFramesToDom(
4638 const FrameRecording& aRecording, double aUnixStartMS) {
4639 auto byteSpan = aRecording.bytes().AsSpan();
4641 nsTArray<DOMCollectedFrame> domFrames;
4643 for (const auto& recordedFrame : aRecording.frames()) {
4644 const uint32_t frameBufferLength = recordedFrame.length();
4645 if (frameBufferLength > byteSpan.Length()) {
4646 return Nothing();
4649 const auto frameSpan = byteSpan.To(frameBufferLength);
4650 byteSpan = byteSpan.From(frameBufferLength);
4652 nsCString dataUri;
4654 dataUri.AppendLiteral("data:image/png;base64,");
4656 nsresult rv =
4657 Base64EncodeAppend(reinterpret_cast<const char*>(frameSpan.Elements()),
4658 frameSpan.Length(), dataUri);
4659 if (NS_FAILED(rv)) {
4660 return Nothing();
4663 DOMCollectedFrame domFrame;
4664 domFrame.mTimeOffset =
4665 (recordedFrame.timeOffset() - aRecording.startTime()).ToMilliseconds();
4666 domFrame.mDataUri = std::move(dataUri);
4668 domFrames.AppendElement(std::move(domFrame));
4671 if (byteSpan.Length() != 0) {
4672 return Nothing();
4675 DOMCollectedFrames result;
4677 result.mRecordingStart = aUnixStartMS;
4678 result.mFrames = std::move(domFrames);
4680 return Some(std::move(result));
4683 NS_IMETHODIMP
4684 nsDOMWindowUtils::StopCompositionRecording(bool aWriteToDisk,
4685 Promise** aOutPromise) {
4686 NS_ENSURE_ARG_POINTER(aOutPromise);
4687 *aOutPromise = nullptr;
4689 nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow);
4690 NS_ENSURE_STATE(outer);
4691 nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
4692 NS_ENSURE_STATE(inner);
4694 ErrorResult err;
4695 RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err);
4696 if (NS_WARN_IF(err.Failed())) {
4697 return err.StealNSResult();
4700 RefPtr<Promise>(promise).forget(aOutPromise);
4702 CompositorBridgeChild* cbc = GetCompositorBridge();
4703 if (NS_WARN_IF(!cbc)) {
4704 promise->MaybeReject(NS_ERROR_UNEXPECTED);
4705 return NS_OK;
4708 cbc->SendEndRecording()->Then(
4709 GetCurrentSerialEventTarget(), __func__,
4710 [promise, aWriteToDisk](Maybe<FrameRecording>&& aRecording) {
4711 if (!aRecording) {
4712 promise->MaybeRejectWithUnknownError("Failed to get frame recording");
4713 return;
4716 // We need to know when the recording started in Unix Time.
4717 // Unfortunately, the recording start time is an opaque Timestamp that
4718 // can only be used to calculate a duration.
4720 // This is not great, but we are going to get Now() twice in close
4721 // proximity, one in Unix Time and the other in Timestamp time. Then we
4722 // can subtract the length of the recording from the current Unix Time
4723 // to get the Unix start time.
4724 const TimeStamp timestampNow = TimeStamp::Now();
4725 const int64_t unixNowUS = PR_Now();
4727 const TimeDuration recordingLength =
4728 timestampNow - aRecording->startTime();
4729 const double unixNowMS = double(unixNowUS) / 1000.0;
4730 const double unixStartMS = unixNowMS - recordingLength.ToMilliseconds();
4732 if (aWriteToDisk) {
4733 if (!WriteRecordingToDisk(*aRecording, unixStartMS)) {
4734 promise->MaybeRejectWithUnknownError(
4735 "Failed to write recording to disk");
4736 return;
4738 promise->MaybeResolveWithUndefined();
4739 } else {
4740 auto maybeDomFrames =
4741 ConvertCompositionRecordingFramesToDom(*aRecording, unixStartMS);
4742 if (!maybeDomFrames) {
4743 promise->MaybeRejectWithUnknownError(
4744 "Unable to base64-encode recorded frames");
4745 return;
4747 promise->MaybeResolve(*maybeDomFrames);
4750 [promise](const mozilla::ipc::ResponseRejectReason&) {
4751 promise->MaybeRejectWithUnknownError(
4752 "IPC failed getting composition recording");
4755 return NS_OK;
4758 NS_IMETHODIMP
4759 nsDOMWindowUtils::SetSystemFont(const nsACString& aFontName) {
4760 nsIWidget* widget = GetWidget();
4761 if (!widget) {
4762 return NS_OK;
4765 nsAutoCString fontName(aFontName);
4766 return widget->SetSystemFont(fontName);
4769 NS_IMETHODIMP
4770 nsDOMWindowUtils::GetSystemFont(nsACString& aFontName) {
4771 nsIWidget* widget = GetWidget();
4772 if (!widget) {
4773 return NS_OK;
4776 nsAutoCString fontName;
4777 widget->GetSystemFont(fontName);
4778 aFontName.Assign(fontName);
4779 return NS_OK;
4782 NS_IMETHODIMP
4783 nsDOMWindowUtils::IsCssPropertyRecordedInUseCounter(const nsACString& aPropName,
4784 bool* aRecorded) {
4785 *aRecorded = false;
4787 Document* doc = GetDocument();
4788 if (!doc || !doc->GetStyleUseCounters()) {
4789 return NS_ERROR_FAILURE;
4792 bool knownProp = false;
4793 *aRecorded = Servo_IsCssPropertyRecordedInUseCounter(
4794 doc->GetStyleUseCounters(), &aPropName, &knownProp);
4795 return knownProp ? NS_OK : NS_ERROR_FAILURE;
4798 NS_IMETHODIMP
4799 nsDOMWindowUtils::IsCoepCredentialless(bool* aResult) {
4800 Document* doc = GetDocument();
4801 if (!doc) {
4802 return NS_ERROR_FAILURE;
4805 *aResult = net::IsCoepCredentiallessEnabled(
4806 doc->Trials().IsEnabled(OriginTrial::CoepCredentialless));
4807 return NS_OK;
4810 NS_IMETHODIMP
4811 nsDOMWindowUtils::GetLayersId(uint64_t* aOutLayersId) {
4812 nsIWidget* widget = GetWidget();
4813 if (!widget) {
4814 return NS_ERROR_FAILURE;
4816 BrowserChild* child = widget->GetOwningBrowserChild();
4817 if (!child) {
4818 return NS_ERROR_FAILURE;
4820 *aOutLayersId = (uint64_t)child->GetLayersId();
4821 return NS_OK;
4824 NS_IMETHODIMP
4825 nsDOMWindowUtils::GetPaintCount(uint64_t* aPaintCount) {
4826 auto* presShell = GetPresShell();
4827 *aPaintCount = presShell ? presShell->GetPaintCount() : 0;
4828 return NS_OK;
4831 NS_IMETHODIMP
4832 nsDOMWindowUtils::GetWebrtcRawDeviceId(nsAString& aRawDeviceId) {
4833 if (!XRE_IsParentProcess()) {
4834 MOZ_CRASH(
4835 "GetWebrtcRawDeviceId is only available in the parent "
4836 "process");
4839 nsIWidget* widget = GetWidget();
4840 if (!widget) {
4841 return NS_ERROR_FAILURE;
4844 int64_t rawDeviceId =
4845 (int64_t)(widget->GetNativeData(NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID));
4846 if (!rawDeviceId) {
4847 return NS_ERROR_FAILURE;
4850 aRawDeviceId.AppendInt(rawDeviceId);
4851 return NS_OK;
4854 NS_IMETHODIMP
4855 nsDOMWindowUtils::GetEffectivelyThrottlesFrameRequests(bool* aResult) {
4856 Document* doc = GetDocument();
4857 if (!doc) {
4858 return NS_ERROR_FAILURE;
4860 *aResult = !doc->WouldScheduleFrameRequestCallbacks() ||
4861 doc->ShouldThrottleFrameRequests();
4862 return NS_OK;
4865 NS_IMETHODIMP
4866 nsDOMWindowUtils::ResetMobileViewportManager() {
4867 if (RefPtr<PresShell> presShell = GetPresShell()) {
4868 if (auto mvm = presShell->GetMobileViewportManager()) {
4869 mvm->SetInitialViewport();
4870 return NS_OK;
4873 // Unable to reset, so let's error out
4874 return NS_ERROR_FAILURE;
4877 NS_IMETHODIMP
4878 nsDOMWindowUtils::GetSuspendedByBrowsingContextGroup(bool* aResult) {
4879 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
4880 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
4882 nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
4883 NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE);
4885 *aResult = inner->GetWasSuspendedByGroup();
4886 return NS_OK;
4889 NS_IMETHODIMP
4890 nsDOMWindowUtils::GetHasScrollLinkedEffect(bool* aResult) {
4891 Document* doc = GetDocument();
4892 if (!doc) {
4893 return NS_ERROR_FAILURE;
4895 *aResult = doc->HasScrollLinkedEffect();
4896 return NS_OK;
4899 NS_IMETHODIMP
4900 nsDOMWindowUtils::GetOrientationLock(uint32_t* aOrientationLock) {
4901 NS_WARNING("nsDOMWindowUtils::GetOrientationLock");
4903 nsIDocShell* docShell = GetDocShell();
4904 if (!docShell) {
4905 return NS_ERROR_FAILURE;
4908 BrowsingContext* bc = docShell->GetBrowsingContext();
4909 bc = bc ? bc->Top() : nullptr;
4910 if (!bc) {
4911 return NS_ERROR_FAILURE;
4914 *aOrientationLock = static_cast<uint32_t>(bc->GetOrientationLock());
4915 return NS_OK;
4918 NS_IMETHODIMP
4919 nsDOMWindowUtils::GetWheelScrollTarget(Element** aResult) {
4920 *aResult = nullptr;
4921 if (nsIFrame* targetFrame = WheelTransaction::GetScrollTargetFrame()) {
4922 NS_IF_ADDREF(*aResult = Element::FromNodeOrNull(targetFrame->GetContent()));
4924 return NS_OK;
4927 NS_IMETHODIMP
4928 nsDOMWindowUtils::SetHiDPIMode(bool aHiDPI) {
4929 #ifdef DEBUG
4930 nsCOMPtr<nsIWidget> widget = GetWidget();
4931 if (!widget) return NS_ERROR_FAILURE;
4933 return widget->SetHiDPIMode(aHiDPI);
4934 #else
4935 return NS_ERROR_NOT_AVAILABLE;
4936 #endif
4939 NS_IMETHODIMP
4940 nsDOMWindowUtils::RestoreHiDPIMode() {
4941 #ifdef DEBUG
4942 nsCOMPtr<nsIWidget> widget = GetWidget();
4943 if (!widget) return NS_ERROR_FAILURE;
4945 return widget->RestoreHiDPIMode();
4946 #else
4947 return NS_ERROR_NOT_AVAILABLE;
4948 #endif