Source code
Revision control
Copy as Markdown
Other Tools
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
#include "nsDOMWindowUtils.h"
#include "LayoutConstants.h"
#include "MobileViewportManager.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "nsPresContext.h"
#include "nsCaret.h"
#include "nsContentList.h"
#include "nsError.h"
#include "nsQueryContentEventResult.h"
#include "nsGlobalWindowOuter.h"
#include "nsFocusManager.h"
#include "nsFrameManager.h"
#include "nsRefreshDriver.h"
#include "nsStyleUtil.h"
#include "mozilla/Base64.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/DOMCollectedFramesBinding.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/Touch.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/SharedStyleSheetCache.h"
#include "mozilla/StaticPrefs_test.h"
#include "mozilla/InputTaskManager.h"
#include "nsIObjectLoadingContent.h"
#include "nsIFrame.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "mozilla/layers/PCompositorBridgeTypes.h"
#include "mozilla/layers/TouchActionHelper.h"
#include "mozilla/media/MediaUtils.h"
#include "nsQueryObject.h"
#include "CubebDeviceEnumerator.h"
#include "nsIScrollableFrame.h"
#include "nsContentUtils.h"
#include "nsIWidget.h"
#include "nsCharsetSource.h"
#include "nsJSEnvironment.h"
#include "nsJSUtils.h"
#include "js/experimental/PCCountProfiling.h" // JS::{Start,Stop}PCCountProfiling, JS::PurgePCCounts, JS::GetPCCountScript{Count,Summary,Contents}
#include "js/Object.h" // JS::GetClass
#include "mozilla/ChaosMode.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/MiscEvents.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/PresShell.h"
#include "mozilla/PresShellInlines.h"
#include "mozilla/Span.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/TextEvents.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/TouchEvents.h"
#include "nsViewManager.h"
#include "nsLayoutUtils.h"
#include "nsComputedDOMStyle.h"
#include "nsCSSProps.h"
#include "nsIDocShell.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileBinding.h"
#include "mozilla/dom/DOMRect.h"
#include <algorithm>
#if defined(MOZ_WIDGET_GTK)
# include <gdk/gdk.h>
# if defined(MOZ_X11)
# include <gdk/gdkx.h>
# include "X11UndefineNone.h"
# endif
#endif
#include "mozilla/dom/AudioDeviceInfo.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/IDBFactoryBinding.h"
#include "mozilla/dom/IndexedDatabaseManager.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/Text.h"
#include "mozilla/dom/quota/PersistenceType.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/layers/FrameUniformityData.h"
#include "nsPrintfCString.h"
#include "nsViewportInfo.h"
#include "nsIFormControl.h"
// #include "nsWidgetsCID.h"
#include "nsDisplayList.h"
#include "nsROCSSPrimitiveValue.h"
#include "nsIBaseWindow.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIInterfaceRequestorUtils.h"
#include "mozilla/Preferences.h"
#include "nsContentPermissionHelper.h"
#include "nsCSSPseudoElements.h" // for PseudoStyleType
#include "nsNetUtil.h"
#include "HTMLImageElement.h"
#include "HTMLCanvasElement.h"
#include "mozilla/css/ImageLoader.h"
#include "mozilla/layers/IAPZCTreeManager.h" // for layers::ZoomToRectBehavior
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/dom/TimeoutManager.h"
#include "mozilla/PreloadedStyleSheet.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/DisplayPortUtils.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/ViewportUtils.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/IMEContentObserver.h"
#include "mozilla/WheelHandlingHelper.h"
#ifdef XP_WIN
# include <direct.h>
#else
# include <sys/stat.h>
#endif
#ifdef XP_WIN
# undef GetClassName
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::widget;
using namespace mozilla::gfx;
class gfxContext;
class OldWindowSize : public LinkedListElement<OldWindowSize> {
public:
static void Set(nsIWeakReference* aWindowRef, const nsSize& aSize) {
OldWindowSize* item = GetItem(aWindowRef);
if (item) {
item->mSize = aSize;
} else {
item = new OldWindowSize(aWindowRef, aSize);
sList.insertBack(item);
}
}
static nsSize GetAndRemove(nsIWeakReference* aWindowRef) {
nsSize result;
if (OldWindowSize* item = GetItem(aWindowRef)) {
result = item->mSize;
delete item;
}
return result;
}
private:
explicit OldWindowSize(nsIWeakReference* aWindowRef, const nsSize& aSize)
: mWindowRef(aWindowRef), mSize(aSize) {}
~OldWindowSize() = default;
;
static OldWindowSize* GetItem(nsIWeakReference* aWindowRef) {
OldWindowSize* item = sList.getFirst();
while (item && item->mWindowRef != aWindowRef) {
item = item->getNext();
}
return item;
}
static LinkedList<OldWindowSize> sList;
nsWeakPtr mWindowRef;
nsSize mSize;
};
namespace {
class NativeInputRunnable final : public PrioritizableRunnable {
explicit NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent);
~NativeInputRunnable() = default;
public:
static already_AddRefed<nsIRunnable> Create(
already_AddRefed<nsIRunnable>&& aEvent);
};
NativeInputRunnable::NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent)
: PrioritizableRunnable(std::move(aEvent),
nsIRunnablePriority::PRIORITY_INPUT_HIGH) {}
/* static */
already_AddRefed<nsIRunnable> NativeInputRunnable::Create(
already_AddRefed<nsIRunnable>&& aEvent) {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIRunnable> event(new NativeInputRunnable(std::move(aEvent)));
return event.forget();
}
} // unnamed namespace
LinkedList<OldWindowSize> OldWindowSize::sList;
NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWindowUtils)
NS_INTERFACE_MAP_ENTRY(nsIDOMWindowUtils)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMWindowUtils)
NS_IMPL_RELEASE(nsDOMWindowUtils)
nsDOMWindowUtils::nsDOMWindowUtils(nsGlobalWindowOuter* aWindow) {
nsCOMPtr<nsISupports> supports = do_QueryObject(aWindow);
mWindow = do_GetWeakReference(supports);
}
nsDOMWindowUtils::~nsDOMWindowUtils() { OldWindowSize::GetAndRemove(mWindow); }
nsIDocShell* nsDOMWindowUtils::GetDocShell() {
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
if (!window) {
return nullptr;
}
return window->GetDocShell();
}
PresShell* nsDOMWindowUtils::GetPresShell() {
nsIDocShell* docShell = GetDocShell();
if (!docShell) {
return nullptr;
}
return docShell->GetPresShell();
}
nsPresContext* nsDOMWindowUtils::GetPresContext() {
nsIDocShell* docShell = GetDocShell();
if (!docShell) {
return nullptr;
}
return docShell->GetPresContext();
}
Document* nsDOMWindowUtils::GetDocument() {
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
if (!window) {
return nullptr;
}
return window->GetExtantDoc();
}
WebRenderBridgeChild* nsDOMWindowUtils::GetWebRenderBridge() {
if (nsIWidget* widget = GetWidget()) {
if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
if (WebRenderLayerManager* wr = renderer->AsWebRender()) {
return wr->WrBridge();
}
}
}
return nullptr;
}
CompositorBridgeChild* nsDOMWindowUtils::GetCompositorBridge() {
if (nsIWidget* widget = GetWidget()) {
if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
if (CompositorBridgeChild* cbc = renderer->GetCompositorBridgeChild()) {
return cbc;
}
}
}
return nullptr;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetLastOverWindowPointerLocationInCSSPixels(float* aX,
float* aY) {
const PresShell* presShell = GetPresShell();
const nsPresContext* presContext = GetPresContext();
if (!presShell || !presContext) {
return NS_ERROR_FAILURE;
}
const nsPoint& lastOverWindowPointerLocation =
presShell->GetLastOverWindowPointerLocation();
if (lastOverWindowPointerLocation.X() == NS_UNCONSTRAINEDSIZE &&
lastOverWindowPointerLocation.Y() == NS_UNCONSTRAINEDSIZE) {
*aX = 0;
*aY = 0;
} else {
const CSSPoint lastOverWindowPointerLocationInCSSPixels =
CSSPoint::FromAppUnits(lastOverWindowPointerLocation);
*aX = lastOverWindowPointerLocationInCSSPixels.X();
*aY = lastOverWindowPointerLocationInCSSPixels.Y();
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SyncFlushCompositor() {
if (nsIWidget* widget = GetWidget()) {
if (WindowRenderer* renderer = widget->GetWindowRenderer()) {
if (KnowsCompositor* kc = renderer->AsKnowsCompositor()) {
kc->SyncWithCompositor();
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetImageAnimationMode(uint16_t* aMode) {
NS_ENSURE_ARG_POINTER(aMode);
*aMode = 0;
nsPresContext* presContext = GetPresContext();
if (presContext) {
*aMode = presContext->ImageAnimationMode();
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetImageAnimationMode(uint16_t aMode) {
nsPresContext* presContext = GetPresContext();
if (presContext) {
presContext->SetImageAnimationMode(aMode);
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetDocCharsetIsForced(bool* aIsForced) {
*aIsForced = false;
Document* doc = GetDocument();
if (doc) {
auto source = doc->GetDocumentCharacterSetSource();
*aIsForced = source == kCharsetFromInitialUserForcedAutoDetection ||
source == kCharsetFromFinalUserForcedAutoDetection;
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetPhysicalMillimeterInCSSPixels(float* aPhysicalMillimeter) {
nsPresContext* presContext = GetPresContext();
if (!presContext) {
return NS_ERROR_NOT_AVAILABLE;
}
*aPhysicalMillimeter = nsPresContext::AppUnitsToFloatCSSPixels(
presContext->PhysicalMillimetersToAppUnits(1));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName,
nsAString& aValue) {
Document* doc = GetDocument();
if (doc) {
RefPtr<nsAtom> name = NS_Atomize(aName);
doc->GetHeaderData(name, aValue);
return NS_OK;
}
aValue.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::UpdateLayerTree() {
if (RefPtr<PresShell> presShell = GetPresShell()) {
// Don't flush throttled animations since it might fire MozAfterPaint event
// (in WebRender it constantly does), thus the reftest harness can't take
// any snapshot until the throttled animations finished.
presShell->FlushPendingNotifications(
ChangesToFlush(FlushType::Display, false /* flush animations */));
RefPtr<nsViewManager> vm = presShell->GetViewManager();
if (nsView* view = vm->GetRootView()) {
nsAutoScriptBlocker scriptBlocker;
presShell->PaintAndRequestComposite(view,
PaintFlags::PaintSyncDecodeImages);
presShell->GetWindowRenderer()->WaitOnTransactionProcessed();
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetDocumentViewerSize(uint32_t* aDisplayWidth,
uint32_t* aDisplayHeight) {
PresShell* presShell = GetPresShell();
LayoutDeviceIntSize displaySize;
if (!presShell || !nsLayoutUtils::GetDocumentViewerSize(
presShell->GetPresContext(), displaySize)) {
return NS_ERROR_FAILURE;
}
*aDisplayWidth = displaySize.width;
*aDisplayHeight = displaySize.height;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetViewportInfo(uint32_t aDisplayWidth,
uint32_t aDisplayHeight, double* aDefaultZoom,
bool* aAllowZoom, double* aMinZoom,
double* aMaxZoom, uint32_t* aWidth,
uint32_t* aHeight, bool* aAutoSize) {
Document* doc = GetDocument();
NS_ENSURE_STATE(doc);
nsViewportInfo info =
doc->GetViewportInfo(ScreenIntSize(aDisplayWidth, aDisplayHeight));
*aDefaultZoom = info.GetDefaultZoom().scale;
*aAllowZoom = info.IsZoomAllowed();
*aMinZoom = info.GetMinZoom().scale;
*aMaxZoom = info.GetMaxZoom().scale;
CSSIntSize size = gfx::RoundedToInt(info.GetSize());
*aWidth = size.width;
*aHeight = size.height;
*aAutoSize = info.IsAutoSizeEnabled();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetViewportFitInfo(nsAString& aViewportFit) {
Document* doc = GetDocument();
NS_ENSURE_STATE(doc);
ViewportMetaData metaData = doc->GetViewportMetaData();
if (metaData.mViewportFit.EqualsLiteral("contain")) {
aViewportFit.AssignLiteral("contain");
} else if (metaData.mViewportFit.EqualsLiteral("cover")) {
aViewportFit.AssignLiteral("cover");
} else {
aViewportFit.AssignLiteral("auto");
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetMousewheelAutodir(Element* aElement, bool aEnabled,
bool aHonourRoot) {
aElement->SetProperty(nsGkAtoms::forceMousewheelAutodir,
reinterpret_cast<void*>(aEnabled));
aElement->SetProperty(nsGkAtoms::forceMousewheelAutodirHonourRoot,
reinterpret_cast<void*>(aHonourRoot));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
float aWidthPx, float aHeightPx,
Element* aElement,
uint32_t aPriority) {
PresShell* presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
if (!aElement) {
return NS_ERROR_INVALID_ARG;
}
if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
return NS_ERROR_INVALID_ARG;
}
bool hadDisplayPort = false;
bool wasPainted = false;
nsRect oldDisplayPort;
{
DisplayPortPropertyData* currentData =
static_cast<DisplayPortPropertyData*>(
aElement->GetProperty(nsGkAtoms::DisplayPort));
if (currentData) {
if (currentData->mPriority > aPriority) {
return NS_OK;
}
hadDisplayPort = true;
oldDisplayPort = currentData->mRect;
wasPainted = currentData->mPainted;
}
}
nsRect displayport(nsPresContext::CSSPixelsToAppUnits(aXPx),
nsPresContext::CSSPixelsToAppUnits(aYPx),
nsPresContext::CSSPixelsToAppUnits(aWidthPx),
nsPresContext::CSSPixelsToAppUnits(aHeightPx));
aElement->RemoveProperty(nsGkAtoms::MinimalDisplayPort);
aElement->SetProperty(
nsGkAtoms::DisplayPort,
new DisplayPortPropertyData(displayport, aPriority, wasPainted),
nsINode::DeleteProperty<DisplayPortPropertyData>);
DisplayPortUtils::InvalidateForDisplayPortChange(aElement, hadDisplayPort,
oldDisplayPort, displayport);
nsIFrame* rootFrame = presShell->GetRootFrame();
if (rootFrame) {
rootFrame->SchedulePaint();
// If we are hiding something that is a display root then send empty paint
// transaction in order to release retained layers because it won't get
// any more paint requests when it is hidden.
if (displayport.IsEmpty() &&
rootFrame == nsLayoutUtils::GetDisplayRootFrame(rootFrame)) {
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
nsLayoutUtils::PaintFrame(
nullptr, rootFrame, nsRegion(), NS_RGB(255, 255, 255),
nsDisplayListBuilderMode::Painting, PaintFrameFlags::WidgetLayers);
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetDisplayPortMarginsForElement(
float aLeftMargin, float aTopMargin, float aRightMargin,
float aBottomMargin, Element* aElement, uint32_t aPriority) {
PresShell* presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
if (!aElement) {
return NS_ERROR_INVALID_ARG;
}
if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
return NS_ERROR_INVALID_ARG;
}
// Note order change of arguments between our function signature and
// ScreenMargin constructor.
ScreenMargin displayportMargins(aTopMargin, aRightMargin, aBottomMargin,
aLeftMargin);
DisplayPortUtils::SetDisplayPortMargins(
aElement, presShell,
DisplayPortMargins::ForContent(aElement, displayportMargins),
DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes, aPriority);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX, int32_t aY,
int32_t aWidth, int32_t aHeight,
Element* aElement) {
PresShell* presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
if (!aElement) {
return NS_ERROR_INVALID_ARG;
}
if (aElement->GetUncomposedDoc() != presShell->GetDocument()) {
return NS_ERROR_INVALID_ARG;
}
DisplayPortUtils::SetDisplayPortBase(aElement,
nsRect(aX, aY, aWidth, aHeight));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetScrollbarSizes(Element* aElement,
uint32_t* aOutVerticalScrollbarWidth,
uint32_t* aOutHorizontalScrollbarHeight) {
nsIScrollableFrame* scrollFrame =
nsLayoutUtils::FindScrollableFrameFor(aElement);
if (!scrollFrame) {
return NS_ERROR_INVALID_ARG;
}
CSSIntMargin scrollbarSizes =
RoundedToInt(CSSMargin::FromAppUnits(scrollFrame->GetActualScrollbarSizes(
nsIScrollableFrame::ScrollbarSizesOptions::
INCLUDE_VISUAL_VIEWPORT_SCROLLBARS)));
*aOutVerticalScrollbarWidth = scrollbarSizes.LeftRight();
*aOutHorizontalScrollbarHeight = scrollbarSizes.TopBottom();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetResolutionAndScaleTo(float aResolution) {
PresShell* presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
presShell->SetResolutionAndScaleTo(aResolution, ResolutionChangeOrigin::Test);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetRestoreResolution(float aResolution,
uint32_t aDisplayWidth,
uint32_t aDisplayHeight) {
PresShell* presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
presShell->SetRestoreResolution(
aResolution, LayoutDeviceIntSize(aDisplayWidth, aDisplayHeight));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetResolution(float* aResolution) {
PresShell* presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
*aResolution = presShell->GetResolution();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetIsFirstPaint(bool aIsFirstPaint) {
if (PresShell* presShell = GetPresShell()) {
presShell->SetIsFirstPaint(aIsFirstPaint);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetIsFirstPaint(bool* aIsFirstPaint) {
if (PresShell* presShell = GetPresShell()) {
*aIsFirstPaint = presShell->GetIsFirstPaint();
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) {
if (PresShell* presShell = GetPresShell()) {
*aPresShellId = presShell->GetPresShellId();
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendMouseEvent(
const nsAString& aType, float aX, float aY, int32_t aButton,
int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
float aPressure, unsigned short aInputSourceArg,
bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized,
int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount,
bool* aPreventDefault) {
return SendMouseEventCommon(
aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame,
aPressure, aInputSourceArg,
aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false,
aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true,
aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false,
aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED);
}
NS_IMETHODIMP
nsDOMWindowUtils::SendMouseEventToWindow(
const nsAString& aType, float aX, float aY, int32_t aButton,
int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
float aPressure, unsigned short aInputSourceArg,
bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized,
int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount) {
AUTO_PROFILER_LABEL("nsDOMWindowUtils::SendMouseEventToWindow", OTHER);
return SendMouseEventCommon(
aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame,
aPressure, aInputSourceArg,
aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true,
nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true,
aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false,
aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED);
}
NS_IMETHODIMP
nsDOMWindowUtils::SendMouseEventCommon(
const nsAString& aType, float aX, float aY, int32_t aButton,
int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame,
float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId,
bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized,
bool aIsWidgetEventSynthesized, int32_t aButtons) {
RefPtr<PresShell> presShell = GetPresShell();
PreventDefaultResult preventDefaultResult;
nsresult rv = nsContentUtils::SendMouseEvent(
presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers,
aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow,
&preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized);
if (aPreventDefault) {
*aPreventDefault = preventDefaultResult != PreventDefaultResult::No;
}
return rv;
}
NS_IMETHODIMP
nsDOMWindowUtils::IsCORSSafelistedRequestHeader(const nsACString& aName,
const nsACString& aValue,
bool* aRetVal) {
NS_ENSURE_ARG_POINTER(aRetVal);
*aRetVal = nsContentUtils::IsCORSSafelistedRequestHeader(aName, aValue);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendWheelEvent(float aX, float aY, double aDeltaX,
double aDeltaY, double aDeltaZ,
uint32_t aDeltaMode, int32_t aModifiers,
int32_t aLineOrPageDeltaX,
int32_t aLineOrPageDeltaY, uint32_t aOptions) {
// get the widget to send the event to
nsPoint offset;
nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
if (!widget) {
return NS_ERROR_NULL_POINTER;
}
WidgetWheelEvent wheelEvent(true, eWheel, widget);
wheelEvent.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
wheelEvent.mDeltaX = aDeltaX;
wheelEvent.mDeltaY = aDeltaY;
wheelEvent.mDeltaZ = aDeltaZ;
wheelEvent.mDeltaMode = aDeltaMode;
wheelEvent.mIsMomentum = (aOptions & WHEEL_EVENT_CAUSED_BY_MOMENTUM) != 0;
wheelEvent.mIsNoLineOrPageDelta =
(aOptions & WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE) != 0;
wheelEvent.mCustomizedByUserPrefs =
(aOptions & WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS) != 0;
wheelEvent.mLineOrPageDeltaX = aLineOrPageDeltaX;
wheelEvent.mLineOrPageDeltaY = aLineOrPageDeltaY;
nsPresContext* presContext = GetPresContext();
NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
wheelEvent.mRefPoint =
nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
if (StaticPrefs::test_events_async_enabled()) {
widget->DispatchInputEvent(&wheelEvent);
} else {
nsEventStatus status = nsEventStatus_eIgnore;
nsresult rv = widget->DispatchEvent(&wheelEvent, status);
NS_ENSURE_SUCCESS(rv, rv);
}
if (widget->AsyncPanZoomEnabled()) {
// Computing overflow deltas is not compatible with APZ, so if APZ is
// enabled, we skip testing it.
return NS_OK;
}
bool failedX = false;
if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_ZERO) &&
wheelEvent.mOverflowDeltaX != 0) {
failedX = true;
}
if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_POSITIVE) &&
wheelEvent.mOverflowDeltaX <= 0) {
failedX = true;
}
if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_NEGATIVE) &&
wheelEvent.mOverflowDeltaX >= 0) {
failedX = true;
}
bool failedY = false;
if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_ZERO) &&
wheelEvent.mOverflowDeltaY != 0) {
failedY = true;
}
if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_POSITIVE) &&
wheelEvent.mOverflowDeltaY <= 0) {
failedY = true;
}
if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_NEGATIVE) &&
wheelEvent.mOverflowDeltaY >= 0) {
failedY = true;
}
#ifdef DEBUG
if (failedX) {
nsPrintfCString debugMsg("SendWheelEvent(): unexpected mOverflowDeltaX: %f",
wheelEvent.mOverflowDeltaX);
NS_WARNING(debugMsg.get());
}
if (failedY) {
nsPrintfCString debugMsg("SendWheelEvent(): unexpected mOverflowDeltaY: %f",
wheelEvent.mOverflowDeltaY);
NS_WARNING(debugMsg.get());
}
#endif
return (!failedX && !failedY) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendTouchEvent(
const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers,
const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs,
const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys,
const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces,
const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs,
const nsTArray<int32_t>& aTwists, int32_t aModifiers,
bool aIgnoreRootScrollFrame, bool* aPreventDefault) {
return SendTouchEventCommon(aType, aIdentifiers, aXs, aYs, aRxs, aRys,
aRotationAngles, aForces, aTiltXs, aTiltYs,
aTwists, aModifiers, aIgnoreRootScrollFrame,
false, aPreventDefault);
}
NS_IMETHODIMP
nsDOMWindowUtils::SendTouchEventToWindow(
const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers,
const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs,
const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys,
const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces,
const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs,
const nsTArray<int32_t>& aTwists, int32_t aModifiers,
bool aIgnoreRootScrollFrame, bool* aPreventDefault) {
return SendTouchEventCommon(aType, aIdentifiers, aXs, aYs, aRxs, aRys,
aRotationAngles, aForces, aTiltXs, aTiltYs,
aTwists, aModifiers, aIgnoreRootScrollFrame, true,
aPreventDefault);
}
nsresult nsDOMWindowUtils::SendTouchEventCommon(
const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers,
const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs,
const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys,
const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces,
const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs,
const nsTArray<int32_t>& aTwists, int32_t aModifiers,
bool aIgnoreRootScrollFrame, bool aToWindow, bool* aPreventDefault) {
// get the widget to send the event to
nsPoint offset;
nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
if (!widget) {
return NS_ERROR_NULL_POINTER;
}
EventMessage msg;
if (aType.EqualsLiteral("touchstart")) {
msg = eTouchStart;
} else if (aType.EqualsLiteral("touchmove")) {
msg = eTouchMove;
} else if (aType.EqualsLiteral("touchend")) {
msg = eTouchEnd;
} else if (aType.EqualsLiteral("touchcancel")) {
msg = eTouchCancel;
} else {
return NS_ERROR_UNEXPECTED;
}
WidgetTouchEvent event(true, msg, widget);
event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
nsPresContext* presContext = GetPresContext();
if (!presContext) {
return NS_ERROR_FAILURE;
}
uint32_t count = aIdentifiers.Length();
if (aXs.Length() != count || aYs.Length() != count ||
aRxs.Length() != count || aRys.Length() != count ||
aRotationAngles.Length() != count || aForces.Length() != count) {
return NS_ERROR_INVALID_ARG;
}
event.mTouches.SetCapacity(count);
for (uint32_t i = 0; i < count; ++i) {
LayoutDeviceIntPoint pt = nsContentUtils::ToWidgetPoint(
CSSPoint(aXs[i], aYs[i]), offset, presContext);
LayoutDeviceIntPoint radius = LayoutDeviceIntPoint::FromAppUnitsRounded(
CSSPoint::ToAppUnits(CSSPoint(aRxs[i], aRys[i])),
presContext->AppUnitsPerDevPixel());
RefPtr<Touch> t = new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i],
aForces[i], aTiltXs[i], aTiltYs[i], aTwists[i]);
event.mTouches.AppendElement(t);
}
nsEventStatus status = nsEventStatus_eIgnore;
if (aToWindow) {
RefPtr<PresShell> presShell;
nsView* view = nsContentUtils::GetViewToDispatchEvent(
presContext, getter_AddRefs(presShell));
if (!presShell || !view) {
return NS_ERROR_FAILURE;
}
*aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
}
if (StaticPrefs::test_events_async_enabled()) {
status = widget->DispatchInputEvent(&event).mContentStatus;
} else {
nsresult rv = widget->DispatchEvent(&event, status);
NS_ENSURE_SUCCESS(rv, rv);
}
if (aPreventDefault) {
*aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
}
return NS_OK;
}
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::CAPS_LOCK) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CAPS_LOCK),
"Need to sync CapsLock value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::NUM_LOCK) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_NUM_LOCK),
"Need to sync NumLock value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::SHIFT_L) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_SHIFT_LEFT),
"Need to sync ShiftLeft value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::SHIFT_R) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_SHIFT_RIGHT),
"Need to sync ShiftRight value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::CTRL_L) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CONTROL_LEFT),
"Need to sync ControlLeft value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::CTRL_R) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CONTROL_RIGHT),
"Need to sync ControlRight value between nsIWidget::Modifiers "
"and nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::ALT_L) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_LEFT),
"Need to sync AltLeft value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::ALT_R) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_RIGHT),
"Need to sync AltRight value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::COMMAND_L) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_COMMAND_LEFT),
"Need to sync CommandLeft value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::COMMAND_R) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_COMMAND_RIGHT),
"Need to sync CommandRight value between nsIWidget::Modifiers "
"and nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::HELP) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_HELP),
"Need to sync Help value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::ALTGRAPH) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_GRAPH),
"Need to sync AltGraph value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(
static_cast<uint32_t>(nsIWidget::Modifiers::FUNCTION) ==
static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_FUNCTION),
"Need to sync Function value between nsIWidget::Modifiers and "
"nsIDOMWindowUtils");
static_assert(static_cast<uint32_t>(nsIWidget::Modifiers::NUMERIC_KEY_PAD) ==
static_cast<uint32_t>(
nsIDOMWindowUtils::NATIVE_MODIFIER_NUMERIC_KEY_PAD),
"Need to sync NumericKeyPad value between nsIWidget::Modifiers "
"and nsIDOMWindowUtils");
static nsIWidget::Modifiers GetWidgetModifiers(uint32_t aNativeModifiers) {
nsIWidget::Modifiers widgetModifiers = static_cast<nsIWidget::Modifiers>(
aNativeModifiers &
(nsIWidget::Modifiers::CAPS_LOCK | nsIWidget::Modifiers::NUM_LOCK |
nsIWidget::Modifiers::SHIFT_L | nsIWidget::Modifiers::SHIFT_R |
nsIWidget::Modifiers::CTRL_L | nsIWidget::Modifiers::CTRL_R |
nsIWidget::Modifiers::ALT_L | nsIWidget::Modifiers::ALT_R |
nsIWidget::Modifiers::COMMAND_L | nsIWidget::Modifiers::COMMAND_R |
nsIWidget::Modifiers::HELP | nsIWidget::Modifiers::ALTGRAPH |
nsIWidget::Modifiers::FUNCTION | nsIWidget::Modifiers::NUMERIC_KEY_PAD));
NS_ASSERTION(static_cast<uint32_t>(widgetModifiers) == aNativeModifiers,
"Invalid value is specified to the native modifiers");
return widgetModifiers;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout,
int32_t aNativeKeyCode,
uint32_t aModifiers,
const nsAString& aCharacters,
const nsAString& aUnmodifiedCharacters,
nsIObserver* aObserver) {
// get the widget to send the event to
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) return NS_ERROR_FAILURE;
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<int32_t, int32_t, uint32_t, nsString, nsString,
nsIObserver*>(
"nsIWidget::SynthesizeNativeKeyEvent", widget,
&nsIWidget::SynthesizeNativeKeyEvent, aNativeKeyboardLayout,
aNativeKeyCode, static_cast<uint32_t>(GetWidgetModifiers(aModifiers)),
aCharacters, aUnmodifiedCharacters, aObserver)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX, int32_t aScreenY,
uint32_t aNativeMessage, int16_t aButton,
uint32_t aModifierFlags,
Element* aElementOnWidget,
nsIObserver* aObserver) {
// get the widget to send the event to
nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElementOnWidget);
if (!widget) {
return NS_ERROR_FAILURE;
}
nsIWidget::NativeMouseMessage message;
switch (aNativeMessage) {
case NATIVE_MOUSE_MESSAGE_BUTTON_DOWN:
message = nsIWidget::NativeMouseMessage::ButtonDown;
break;
case NATIVE_MOUSE_MESSAGE_BUTTON_UP:
message = nsIWidget::NativeMouseMessage::ButtonUp;
break;
case NATIVE_MOUSE_MESSAGE_MOVE:
message = nsIWidget::NativeMouseMessage::Move;
break;
case NATIVE_MOUSE_MESSAGE_ENTER_WINDOW:
message = nsIWidget::NativeMouseMessage::EnterWindow;
break;
case NATIVE_MOUSE_MESSAGE_LEAVE_WINDOW:
message = nsIWidget::NativeMouseMessage::LeaveWindow;
break;
default:
return NS_ERROR_INVALID_ARG;
}
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<LayoutDeviceIntPoint, nsIWidget::NativeMouseMessage,
MouseButton, nsIWidget::Modifiers, nsIObserver*>(
"nsIWidget::SynthesizeNativeMouseEvent", widget,
&nsIWidget::SynthesizeNativeMouseEvent,
LayoutDeviceIntPoint(aScreenX, aScreenY), message,
static_cast<MouseButton>(aButton), GetWidgetModifiers(aModifierFlags),
aObserver)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendNativeMouseScrollEvent(
int32_t aScreenX, int32_t aScreenY, uint32_t aNativeMessage, double aDeltaX,
double aDeltaY, double aDeltaZ, uint32_t aModifierFlags,
uint32_t aAdditionalFlags, Element* aElement, nsIObserver* aObserver) {
// get the widget to send the event to
nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement);
if (!widget) {
return NS_ERROR_FAILURE;
}
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<mozilla::LayoutDeviceIntPoint, uint32_t, double, double,
double, uint32_t, uint32_t, nsIObserver*>(
"nsIWidget::SynthesizeNativeMouseScrollEvent", widget,
&nsIWidget::SynthesizeNativeMouseScrollEvent,
LayoutDeviceIntPoint(aScreenX, aScreenY), aNativeMessage, aDeltaX,
aDeltaY, aDeltaZ, aModifierFlags, aAdditionalFlags, aObserver)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendNativeTouchPoint(uint32_t aPointerId,
uint32_t aTouchState, int32_t aScreenX,
int32_t aScreenY, double aPressure,
uint32_t aOrientation,
nsIObserver* aObserver) {
// FYI: This was designed for automated tests, but currently, this is used by
// DevTools to emulate touch events from mouse events in the responsive
// design mode.
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
if (aPressure < 0 || aPressure > 1 || aOrientation > 359) {
return NS_ERROR_INVALID_ARG;
}
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<uint32_t, nsIWidget::TouchPointerState,
LayoutDeviceIntPoint, double, uint32_t, nsIObserver*>(
"nsIWidget::SynthesizeNativeTouchPoint", widget,
&nsIWidget::SynthesizeNativeTouchPoint, aPointerId,
(nsIWidget::TouchPointerState)aTouchState,
LayoutDeviceIntPoint(aScreenX, aScreenY), aPressure, aOrientation,
aObserver)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendNativeTouchpadPinch(uint32_t aEventPhase, float aScale,
int32_t aScreenX, int32_t aScreenY,
int32_t aModifierFlags) {
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<nsIWidget::TouchpadGesturePhase, float,
LayoutDeviceIntPoint, int32_t>(
"nsIWidget::SynthesizeNativeTouchPadPinch", widget,
&nsIWidget::SynthesizeNativeTouchPadPinch,
(nsIWidget::TouchpadGesturePhase)aEventPhase, aScale,
LayoutDeviceIntPoint(aScreenX, aScreenY), aModifierFlags)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendNativeTouchTap(int32_t aScreenX, int32_t aScreenY,
bool aLongTap, nsIObserver* aObserver) {
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<LayoutDeviceIntPoint, bool, nsIObserver*>(
"nsIWidget::SynthesizeNativeTouchTap", widget,
&nsIWidget::SynthesizeNativeTouchTap,
LayoutDeviceIntPoint(aScreenX, aScreenY), aLongTap, aObserver)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendNativePenInput(uint32_t aPointerId,
uint32_t aPointerState, int32_t aScreenX,
int32_t aScreenY, double aPressure,
uint32_t aRotation, int32_t aTiltX,
int32_t aTiltY, int32_t aButton,
nsIObserver* aObserver) {
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
if (aPressure < 0 || aPressure > 1 || aRotation > 359 || aTiltX < -90 ||
aTiltX > 90 || aTiltY < -90 || aTiltY > 90) {
return NS_ERROR_INVALID_ARG;
}
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<uint32_t, nsIWidget::TouchPointerState,
LayoutDeviceIntPoint, double, uint32_t, int32_t,
int32_t, int32_t, nsIObserver*>(
"nsIWidget::SynthesizeNativePenInput", widget,
&nsIWidget::SynthesizeNativePenInput, aPointerId,
(nsIWidget::TouchPointerState)aPointerState,
LayoutDeviceIntPoint(aScreenX, aScreenY), aPressure, aRotation,
aTiltX, aTiltY, aButton, aObserver)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendNativeTouchpadDoubleTap(int32_t aScreenX,
int32_t aScreenY,
int32_t aModifierFlags) {
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(aModifierFlags >= 0);
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<LayoutDeviceIntPoint, uint32_t>(
"nsIWidget::SynthesizeNativeTouchpadDoubleTap", widget,
&nsIWidget::SynthesizeNativeTouchpadDoubleTap,
LayoutDeviceIntPoint(aScreenX, aScreenY), aModifierFlags)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendNativeTouchpadPan(uint32_t aEventPhase, int32_t aScreenX,
int32_t aScreenY, double aDeltaX,
double aDeltaY, int32_t aModifierFlags,
nsIObserver* aObserver) {
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(aModifierFlags >= 0);
NS_DispatchToMainThread(NativeInputRunnable::Create(
NewRunnableMethod<nsIWidget::TouchpadGesturePhase, LayoutDeviceIntPoint,
double, double, uint32_t, nsIObserver*>(
"nsIWidget::SynthesizeNativeTouchpadPan", widget,
&nsIWidget::SynthesizeNativeTouchpadPan,
(nsIWidget::TouchpadGesturePhase)aEventPhase,
LayoutDeviceIntPoint(aScreenX, aScreenY), aDeltaX, aDeltaY,
aModifierFlags, aObserver)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SuppressAnimation(bool aSuppress) {
nsIWidget* widget = GetWidget();
if (widget) {
widget->SuppressAnimation(aSuppress);
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::ClearSharedStyleSheetCache() {
SharedStyleSheetCache::Clear();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetParsedStyleSheets(uint32_t* aSheets) {
RefPtr<Document> doc = GetDocument();
if (!doc) {
return NS_ERROR_UNEXPECTED;
}
*aSheets = doc->CSSLoader()->ParsedSheetCount();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::ClearNativeTouchSequence(nsIObserver* aObserver) {
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
NS_DispatchToMainThread(
NativeInputRunnable::Create(NewRunnableMethod<nsIObserver*>(
"nsIWidget::ClearNativeTouchSequence", widget,
&nsIWidget::ClearNativeTouchSequence, aObserver)));
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::ActivateNativeMenuItemAt(const nsAString& indexString) {
// get the widget to send the event to
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) return NS_ERROR_FAILURE;
return widget->ActivateNativeMenuItemAt(indexString);
}
NS_IMETHODIMP
nsDOMWindowUtils::ForceUpdateNativeMenuAt(const nsAString& indexString) {
// get the widget to send the event to
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) return NS_ERROR_FAILURE;
return widget->ForceUpdateNativeMenuAt(indexString);
}
NS_IMETHODIMP
nsDOMWindowUtils::GetSelectionAsPlaintext(nsAString& aResult) {
// Get the widget to send the event to.
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
return widget->GetSelectionAsPlaintext(aResult);
}
nsIWidget* nsDOMWindowUtils::GetWidget(nsPoint* aOffset) {
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
if (window) {
nsIDocShell* docShell = window->GetDocShell();
if (docShell) {
return nsContentUtils::GetWidget(docShell->GetPresShell(), aOffset);
}
}
return nullptr;
}
nsIWidget* nsDOMWindowUtils::GetWidgetForElement(Element* aElement) {
if (!aElement) {
return GetWidget();
}
if (Document* doc = aElement->GetUncomposedDoc()) {
if (PresShell* presShell = doc->GetPresShell()) {
nsIFrame* frame = aElement->GetPrimaryFrame();
if (!frame) {
frame = presShell->GetRootFrame();
}
if (frame) {
return frame->GetNearestWidget();
}
}
}
return nullptr;
}
NS_IMETHODIMP
nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener* aListener) {
AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GCCC);
nsJSContext::GarbageCollectNow(JS::GCReason::DOM_UTILS);
nsJSContext::CycleCollectNow(CCReason::API, aListener);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener* aListener) {
nsJSContext::CycleCollectNow(CCReason::API, aListener);
return NS_OK;
}
static bool ParseGCReason(const nsACString& aStr, JS::GCReason* aReason,
JS::GCReason aDefault) {
if (aStr.IsEmpty()) {
*aReason = aDefault;
return true;
}
#define CHECK_REASON(name, _) \
if (aStr.EqualsIgnoreCase(#name)) { \
*aReason = JS::GCReason::name; \
return true; \
}
GCREASONS(CHECK_REASON);
return false;
}
NS_IMETHODIMP
nsDOMWindowUtils::RunNextCollectorTimer(const nsACString& aReason) {
JS::GCReason reason;
if (!ParseGCReason(aReason, &reason, JS::GCReason::DOM_WINDOW_UTILS)) {
return NS_ERROR_INVALID_ARG;
}
nsJSContext::RunNextCollectorTimer(reason);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::PokeGC(const nsACString& aReason) {
JS::GCReason reason;
if (!ParseGCReason(aReason, &reason, JS::GCReason::DOM_WINDOW_UTILS)) {
return NS_ERROR_INVALID_ARG;
}
nsJSContext::PokeGC(reason, nullptr);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType, float aX,
float aY, uint32_t aDirection,
double aDelta, int32_t aModifiers,
uint32_t aClickCount) {
// get the widget to send the event to
nsPoint offset;
nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
if (!widget) return NS_ERROR_FAILURE;
EventMessage msg;
if (aType.EqualsLiteral("MozSwipeGestureMayStart")) {
msg = eSwipeGestureMayStart;
} else if (aType.EqualsLiteral("MozSwipeGestureStart")) {
msg = eSwipeGestureStart;
} else if (aType.EqualsLiteral("MozSwipeGestureUpdate")) {
msg = eSwipeGestureUpdate;
} else if (aType.EqualsLiteral("MozSwipeGestureEnd")) {
msg = eSwipeGestureEnd;
} else if (aType.EqualsLiteral("MozSwipeGesture")) {
msg = eSwipeGesture;
} else if (aType.EqualsLiteral("MozMagnifyGestureStart")) {
msg = eMagnifyGestureStart;
} else if (aType.EqualsLiteral("MozMagnifyGestureUpdate")) {
msg = eMagnifyGestureUpdate;
} else if (aType.EqualsLiteral("MozMagnifyGesture")) {
msg = eMagnifyGesture;
} else if (aType.EqualsLiteral("MozRotateGestureStart")) {
msg = eRotateGestureStart;
} else if (aType.EqualsLiteral("MozRotateGestureUpdate")) {
msg = eRotateGestureUpdate;
} else if (aType.EqualsLiteral("MozRotateGesture")) {
msg = eRotateGesture;
} else if (aType.EqualsLiteral("MozTapGesture")) {
msg = eTapGesture;
} else if (aType.EqualsLiteral("MozPressTapGesture")) {
msg = ePressTapGesture;
} else if (aType.EqualsLiteral("MozEdgeUIStarted")) {
msg = eEdgeUIStarted;
} else if (aType.EqualsLiteral("MozEdgeUICanceled")) {
msg = eEdgeUICanceled;
} else if (aType.EqualsLiteral("MozEdgeUICompleted")) {
msg = eEdgeUICompleted;
} else {
return NS_ERROR_FAILURE;
}
WidgetSimpleGestureEvent event(true, msg, widget);
event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
event.mDirection = aDirection;
event.mDelta = aDelta;
event.mClickCount = aClickCount;
nsPresContext* presContext = GetPresContext();
if (!presContext) return NS_ERROR_FAILURE;
event.mRefPoint =
nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
nsEventStatus status;
return widget->DispatchEvent(&event, status);
}
NS_IMETHODIMP
nsDOMWindowUtils::ElementFromPoint(float aX, float aY,
bool aIgnoreRootScrollFrame,
bool aFlushLayout, Element** aReturn) {
nsCOMPtr<Document> doc = GetDocument();
NS_ENSURE_STATE(doc);
RefPtr<Element> el = doc->ElementFromPointHelper(
aX, aY, aIgnoreRootScrollFrame, aFlushLayout, ViewportType::Layout);
el.forget(aReturn);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::NodesFromRect(float aX, float aY, float aTopSize,
float aRightSize, float aBottomSize,
float aLeftSize, bool aIgnoreRootScrollFrame,
bool aFlushLayout, bool aOnlyVisible,
float aVisibleThreshold,
nsINodeList** aReturn) {
RefPtr<Document> doc = GetDocument();
NS_ENSURE_STATE(doc);
auto list = MakeRefPtr<nsSimpleContentList>(doc);
// The visible threshold was omitted or given a zero value (which makes no
// sense), so give a reasonable default.
if (aVisibleThreshold == 0.0f) {
aVisibleThreshold = 1.0f;
}
AutoTArray<RefPtr<nsINode>, 8> nodes;
doc->NodesFromRect(aX, aY, aTopSize, aRightSize, aBottomSize, aLeftSize,
aIgnoreRootScrollFrame, aFlushLayout, aOnlyVisible,
aVisibleThreshold, nodes);
list->SetCapacity(nodes.Length());
for (auto& node : nodes) {
list->AppendElement(node->AsContent());
}
list.forget(aReturn);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetTranslationNodes(nsINode* aRoot,
nsITranslationNodeList** aRetVal) {
NS_ENSURE_ARG_POINTER(aRetVal);
nsCOMPtr<nsIContent> root = do_QueryInterface(aRoot);