diff options
Diffstat (limited to 'dom/base/nsDOMWindowUtils.cpp')
-rw-r--r-- | dom/base/nsDOMWindowUtils.cpp | 4156 |
1 files changed, 4156 insertions, 0 deletions
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp new file mode 100644 index 000000000..291df5f27 --- /dev/null +++ b/dom/base/nsDOMWindowUtils.cpp @@ -0,0 +1,4156 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsDOMWindowUtils.h" + +#include "mozilla/layers/CompositorBridgeChild.h" +#include "mozilla/layers/LayerTransactionChild.h" +#include "nsPresContext.h" +#include "nsDOMClassInfoID.h" +#include "nsError.h" +#include "nsIDOMEvent.h" +#include "nsQueryContentEventResult.h" +#include "nsGlobalWindow.h" +#include "nsIDocument.h" +#include "nsFocusManager.h" +#include "nsFrameManager.h" +#include "nsRefreshDriver.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/BlobBinding.h" +#include "mozilla/dom/Touch.h" +#include "mozilla/PendingAnimationTracker.h" +#include "nsIObjectLoadingContent.h" +#include "nsFrame.h" +#include "mozilla/layers/ShadowLayers.h" +#include "mozilla/layers/APZCCallbackHelper.h" +#include "ClientLayerManager.h" +#include "nsQueryObject.h" +#ifdef MOZ_FMP4 +#include "MP4Decoder.h" +#endif +#include "CubebUtils.h" + +#include "nsIScrollableFrame.h" + +#include "nsContentUtils.h" + +#include "nsIFrame.h" +#include "nsIWidget.h" +#include "nsCharsetSource.h" +#include "nsJSEnvironment.h" +#include "nsJSUtils.h" + +#include "mozilla/ChaosMode.h" +#include "mozilla/EventStateManager.h" +#include "mozilla/MiscEvents.h" +#include "mozilla/MouseEvents.h" +#include "mozilla/TextEvents.h" +#include "mozilla/TextEventDispatcher.h" +#include "mozilla/TouchEvents.h" + +#include "nsViewManager.h" + +#include "nsIDOMHTMLCanvasElement.h" +#include "nsLayoutUtils.h" +#include "nsComputedDOMStyle.h" +#include "nsIPresShell.h" +#include "nsCSSProps.h" +#include "nsTArrayHelpers.h" +#include "nsIDocShell.h" +#include "nsIContentViewer.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_X11) && defined(MOZ_WIDGET_GTK) +#include <gdk/gdk.h> +#include <gdk/gdkx.h> +#endif + +#include "Layers.h" +#include "gfxPrefs.h" + +#include "mozilla/dom/Element.h" +#include "mozilla/dom/TabChild.h" +#include "mozilla/dom/IDBFactoryBinding.h" +#include "mozilla/dom/IDBMutableFileBinding.h" +#include "mozilla/dom/IDBMutableFile.h" +#include "mozilla/dom/IndexedDatabaseManager.h" +#include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/quota/PersistenceType.h" +#include "mozilla/dom/quota/QuotaManager.h" +#include "mozilla/layers/FrameUniformityData.h" +#include "mozilla/layers/ShadowLayers.h" +#include "nsPrintfCString.h" +#include "nsViewportInfo.h" +#include "nsIFormControl.h" +#include "nsIScriptError.h" +//#include "nsWidgetsCID.h" +#include "FrameLayerBuilder.h" +#include "nsDisplayList.h" +#include "nsROCSSPrimitiveValue.h" +#include "nsIBaseWindow.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIInterfaceRequestorUtils.h" +#include "GeckoProfiler.h" +#include "mozilla/Preferences.h" +#include "nsIContentIterator.h" +#include "nsIDOMStyleSheet.h" +#include "nsIStyleSheetService.h" +#include "nsContentPermissionHelper.h" +#include "nsCSSPseudoElements.h" // for CSSPseudoElementType +#include "nsNetUtil.h" +#include "nsDocument.h" +#include "HTMLImageElement.h" +#include "mozilla/css/ImageLoader.h" +#include "mozilla/layers/APZCTreeManager.h" // for layers::ZoomToRectBehavior +#include "mozilla/dom/Promise.h" +#include "mozilla/StyleSheetInlines.h" +#include "mozilla/gfx/GPUProcessManager.h" + +#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() { }; + + 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; +}; + +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(nsGlobalWindow *aWindow) +{ + nsCOMPtr<nsISupports> supports = do_QueryObject(aWindow); + mWindow = do_GetWeakReference(supports); + NS_ASSERTION(aWindow->IsOuterWindow(), "How did that happen?"); +} + +nsDOMWindowUtils::~nsDOMWindowUtils() +{ + OldWindowSize::GetAndRemove(mWindow); +} + +nsIPresShell* +nsDOMWindowUtils::GetPresShell() +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + if (!window) + return nullptr; + + nsIDocShell *docShell = window->GetDocShell(); + if (!docShell) + return nullptr; + + return docShell->GetPresShell(); +} + +nsPresContext* +nsDOMWindowUtils::GetPresContext() +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + if (!window) + return nullptr; + nsIDocShell *docShell = window->GetDocShell(); + if (!docShell) + return nullptr; + RefPtr<nsPresContext> presContext; + docShell->GetPresContext(getter_AddRefs(presContext)); + return presContext; +} + +nsIDocument* +nsDOMWindowUtils::GetDocument() +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + if (!window) { + return nullptr; + } + return window->GetExtantDoc(); +} + +LayerTransactionChild* +nsDOMWindowUtils::GetLayerTransaction() +{ + nsIWidget* widget = GetWidget(); + if (!widget) + return nullptr; + + LayerManager* manager = widget->GetLayerManager(); + if (!manager) + return nullptr; + + ShadowLayerForwarder* forwarder = manager->AsShadowForwarder(); + return forwarder && forwarder->HasShadowManager() ? + forwarder->GetShadowManager() : + nullptr; +} + +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; + + nsIDocument* doc = GetDocument(); + *aIsForced = doc && + doc->GetDocumentCharacterSetSource() >= kCharsetFromParentForced; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName, + nsAString& aValue) +{ + nsIDocument* doc = GetDocument(); + if (doc) { + nsCOMPtr<nsIAtom> name = NS_Atomize(aName); + doc->GetHeaderData(name, aValue); + return NS_OK; + } + + aValue.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::Redraw(uint32_t aCount, uint32_t *aDurationOut) +{ + if (aCount == 0) + aCount = 1; + + if (nsIPresShell* presShell = GetPresShell()) { + nsIFrame *rootFrame = presShell->GetRootFrame(); + + if (rootFrame) { + PRIntervalTime iStart = PR_IntervalNow(); + + for (uint32_t i = 0; i < aCount; i++) + rootFrame->InvalidateFrame(); + +#if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK) + XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), False); +#endif + + *aDurationOut = PR_IntervalToMilliseconds(PR_IntervalNow() - iStart); + + return NS_OK; + } + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDOMWindowUtils::UpdateLayerTree() +{ + if (nsIPresShell* presShell = GetPresShell()) { + presShell->FlushPendingNotifications(Flush_Display); + RefPtr<nsViewManager> vm = presShell->GetViewManager(); + nsView* view = vm->GetRootView(); + if (view) { + presShell->Paint(view, view->GetBounds(), + nsIPresShell::PAINT_LAYERS | nsIPresShell::PAINT_SYNC_DECODE_IMAGES); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetContentViewerSize(uint32_t *aDisplayWidth, uint32_t *aDisplayHeight) +{ + nsIPresShell* presShell = GetPresShell(); + LayoutDeviceIntSize displaySize; + + if (!presShell || !nsLayoutUtils::GetContentViewerSize(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) +{ + nsIDocument* 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::SetDisplayPortForElement(float aXPx, float aYPx, + float aWidthPx, float aHeightPx, + nsIDOMElement* aElement, + uint32_t aPriority) +{ + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + if (!aElement) { + return NS_ERROR_INVALID_ARG; + } + + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); + + if (!content) { + return NS_ERROR_INVALID_ARG; + } + + if (content->GetUncomposedDoc() != presShell->GetDocument()) { + return NS_ERROR_INVALID_ARG; + } + + DisplayPortPropertyData* currentData = + static_cast<DisplayPortPropertyData*>(content->GetProperty(nsGkAtoms::DisplayPort)); + if (currentData && currentData->mPriority > aPriority) { + return NS_OK; + } + + nsRect displayport(nsPresContext::CSSPixelsToAppUnits(aXPx), + nsPresContext::CSSPixelsToAppUnits(aYPx), + nsPresContext::CSSPixelsToAppUnits(aWidthPx), + nsPresContext::CSSPixelsToAppUnits(aHeightPx)); + + content->SetProperty(nsGkAtoms::DisplayPort, + new DisplayPortPropertyData(displayport, aPriority), + nsINode::DeleteProperty<DisplayPortPropertyData>); + + if (gfxPrefs::LayoutUseContainersForRootFrames()) { + nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); + if (rootScrollFrame && + content == rootScrollFrame->GetContent() && + nsLayoutUtils::UsesAsyncScrolling(rootScrollFrame)) + { + // We are setting a root displayport for a document. + // The pres shell needs a special flag set. + presShell->SetIgnoreViewportScrolling(true); + } + } + + nsIFrame* rootFrame = presShell->FrameManager()->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) { + LayerManager* manager = widget->GetLayerManager(); + manager->BeginTransaction(); + using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags; + nsLayoutUtils::PaintFrame(nullptr, rootFrame, nsRegion(), + NS_RGB(255, 255, 255), + nsDisplayListBuilderMode::PAINTING, + PaintFrameFlags::PAINT_WIDGET_LAYERS | + PaintFrameFlags::PAINT_EXISTING_TRANSACTION); + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetDisplayPortMarginsForElement(float aLeftMargin, + float aTopMargin, + float aRightMargin, + float aBottomMargin, + nsIDOMElement* aElement, + uint32_t aPriority) +{ + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + if (!aElement) { + return NS_ERROR_INVALID_ARG; + } + + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); + + if (!content) { + return NS_ERROR_INVALID_ARG; + } + + if (content->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); + + nsLayoutUtils::SetDisplayPortMargins(content, presShell, displayportMargins, + aPriority); + + return NS_OK; +} + + +NS_IMETHODIMP +nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX, + int32_t aY, + int32_t aWidth, + int32_t aHeight, + nsIDOMElement* aElement) +{ + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + if (!aElement) { + return NS_ERROR_INVALID_ARG; + } + + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); + + if (!content) { + return NS_ERROR_INVALID_ARG; + } + + if (content->GetUncomposedDoc() != presShell->GetDocument()) { + return NS_ERROR_INVALID_ARG; + } + + nsLayoutUtils::SetDisplayPortBase(content, nsRect(aX, aY, aWidth, aHeight)); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetResolution(float aResolution) +{ + if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + presShell->SetResolution(aResolution); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetResolutionAndScaleTo(float aResolution) +{ + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + presShell->SetResolutionAndScaleTo(aResolution); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetRestoreResolution(float aResolution, + uint32_t aDisplayWidth, + uint32_t aDisplayHeight) +{ + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + presShell->SetRestoreResolution(aResolution, + LayoutDeviceIntSize(aDisplayWidth, aDisplayHeight)); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetResolution(float* aResolution) +{ + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + *aResolution = presShell->GetResolution(); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetIsResolutionSet(bool* aIsResolutionSet) { + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + *aIsResolutionSet = presShell->IsResolutionSet(); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetIsFirstPaint(bool aIsFirstPaint) +{ + if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + nsIPresShell* presShell = GetPresShell(); + if (presShell) { + presShell->SetIsFirstPaint(aIsFirstPaint); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetIsFirstPaint(bool *aIsFirstPaint) +{ + if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + nsIPresShell* presShell = GetPresShell(); + if (presShell) { + *aIsFirstPaint = presShell->GetIsFirstPaint(); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetPresShellId(uint32_t *aPresShellId) +{ + nsIPresShell* presShell = GetPresShell(); + if (presShell) { + *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, + uint8_t aOptionalArgCount, + bool *aPreventDefault) +{ + return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers, + aIgnoreRootScrollFrame, aPressure, + aInputSourceArg, 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, + uint8_t aOptionalArgCount) +{ + PROFILER_LABEL("nsDOMWindowUtils", "SendMouseEventToWindow", + js::ProfileEntry::Category::EVENTS); + + return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers, + aIgnoreRootScrollFrame, aPressure, + aInputSourceArg, 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, + bool aToWindow, + bool *aPreventDefault, + bool aIsDOMEventSynthesized, + bool aIsWidgetEventSynthesized, + int32_t aButtons) +{ + nsCOMPtr<nsIPresShell> presShell = GetPresShell(); + return nsContentUtils::SendMouseEvent(presShell, aType, aX, aY, aButton, + aButtons, aClickCount, aModifiers, aIgnoreRootScrollFrame, aPressure, + aInputSourceArg, aToWindow, aPreventDefault, aIsDOMEventSynthesized, + aIsWidgetEventSynthesized); +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendPointerEventCommon(const nsAString& aType, + float aX, + float aY, + int32_t aButton, + int32_t aClickCount, + int32_t aModifiers, + bool aIgnoreRootScrollFrame, + float aPressure, + unsigned short aInputSourceArg, + int32_t aPointerId, + int32_t aWidth, + int32_t aHeight, + int32_t aTiltX, + int32_t aTiltY, + bool aIsPrimary, + bool aIsSynthesized, + uint8_t aOptionalArgCount, + bool aToWindow, + bool* aPreventDefault) +{ + // 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("pointerdown")) { + msg = ePointerDown; + } else if (aType.EqualsLiteral("pointerup")) { + msg = ePointerUp; + } else if (aType.EqualsLiteral("pointermove")) { + msg = ePointerMove; + } else if (aType.EqualsLiteral("pointerover")) { + msg = ePointerOver; + } else if (aType.EqualsLiteral("pointerout")) { + msg = ePointerOut; + } else { + return NS_ERROR_FAILURE; + } + + if (aInputSourceArg == nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN) { + aInputSourceArg = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE; + } + + WidgetPointerEvent event(true, msg, widget); + event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers); + event.button = aButton; + event.buttons = nsContentUtils::GetButtonsFlagForButton(aButton); + event.pressure = aPressure; + event.inputSource = aInputSourceArg; + event.pointerId = aPointerId; + event.mWidth = aWidth; + event.mHeight = aHeight; + event.tiltX = aTiltX; + event.tiltY = aTiltY; + event.mIsPrimary = + (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == aInputSourceArg) ? true : aIsPrimary; + event.mClickCount = aClickCount; + event.mTime = PR_IntervalNow(); + event.mFlags.mIsSynthesizedForTests = aOptionalArgCount >= 10 ? aIsSynthesized : true; + + nsPresContext* presContext = GetPresContext(); + if (!presContext) { + return NS_ERROR_FAILURE; + } + + event.mRefPoint = + nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext); + event.mIgnoreRootScrollFrame = aIgnoreRootScrollFrame; + + nsEventStatus status; + if (aToWindow) { + nsCOMPtr<nsIPresShell> presShell; + nsView* view = nsContentUtils::GetViewToDispatchEvent(presContext, getter_AddRefs(presShell)); + if (!presShell || !view) { + return NS_ERROR_FAILURE; + } + status = nsEventStatus_eIgnore; + return presShell->HandleEvent(view->GetFrame(), &event, false, &status); + } + nsresult rv = widget->DispatchEvent(&event, status); + if (aPreventDefault) { + *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault); + } + + return rv; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendPointerEvent(const nsAString& aType, + float aX, + float aY, + int32_t aButton, + int32_t aClickCount, + int32_t aModifiers, + bool aIgnoreRootScrollFrame, + float aPressure, + unsigned short aInputSourceArg, + int32_t aPointerId, + int32_t aWidth, + int32_t aHeight, + int32_t aTiltX, + int32_t aTiltY, + bool aIsPrimary, + bool aIsSynthesized, + uint8_t aOptionalArgCount, + bool* aPreventDefault) +{ + PROFILER_LABEL("nsDOMWindowUtils", "SendPointerEvent", + js::ProfileEntry::Category::EVENTS); + + return SendPointerEventCommon(aType, aX, aY, aButton, aClickCount, + aModifiers, aIgnoreRootScrollFrame, + aPressure, aInputSourceArg, aPointerId, + aWidth, aHeight, aTiltX, aTiltY, + aIsPrimary, aIsSynthesized, + aOptionalArgCount, false, aPreventDefault); +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendPointerEventToWindow(const nsAString& aType, + float aX, + float aY, + int32_t aButton, + int32_t aClickCount, + int32_t aModifiers, + bool aIgnoreRootScrollFrame, + float aPressure, + unsigned short aInputSourceArg, + int32_t aPointerId, + int32_t aWidth, + int32_t aHeight, + int32_t aTiltX, + int32_t aTiltY, + bool aIsPrimary, + bool aIsSynthesized, + uint8_t aOptionalArgCount) +{ + PROFILER_LABEL("nsDOMWindowUtils", "SendPointerEventToWindow", + js::ProfileEntry::Category::EVENTS); + + return SendPointerEventCommon(aType, aX, aY, aButton, aClickCount, + aModifiers, aIgnoreRootScrollFrame, + aPressure, aInputSourceArg, aPointerId, + aWidth, aHeight, aTiltX, aTiltY, + aIsPrimary, aIsSynthesized, + aOptionalArgCount, true, nullptr); +} + +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; + + wheelEvent.mTime = PR_Now() / 1000; + + nsPresContext* presContext = GetPresContext(); + NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); + + wheelEvent.mRefPoint = + nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext); + + widget->DispatchInputEvent(&wheelEvent); + + 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, + uint32_t *aIdentifiers, + int32_t *aXs, + int32_t *aYs, + uint32_t *aRxs, + uint32_t *aRys, + float *aRotationAngles, + float *aForces, + uint32_t aCount, + int32_t aModifiers, + bool aIgnoreRootScrollFrame, + bool *aPreventDefault) +{ + return SendTouchEventCommon(aType, aIdentifiers, aXs, aYs, aRxs, aRys, + aRotationAngles, aForces, aCount, aModifiers, + aIgnoreRootScrollFrame, false, aPreventDefault); +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendTouchEventToWindow(const nsAString& aType, + uint32_t* aIdentifiers, + int32_t* aXs, + int32_t* aYs, + uint32_t* aRxs, + uint32_t* aRys, + float* aRotationAngles, + float* aForces, + uint32_t aCount, + int32_t aModifiers, + bool aIgnoreRootScrollFrame, + bool* aPreventDefault) +{ + return SendTouchEventCommon(aType, aIdentifiers, aXs, aYs, aRxs, aRys, + aRotationAngles, aForces, aCount, aModifiers, + aIgnoreRootScrollFrame, true, aPreventDefault); +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendTouchEventCommon(const nsAString& aType, + uint32_t* aIdentifiers, + int32_t* aXs, + int32_t* aYs, + uint32_t* aRxs, + uint32_t* aRys, + float* aRotationAngles, + float* aForces, + uint32_t aCount, + 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); + event.mTime = PR_Now(); + + nsPresContext* presContext = GetPresContext(); + if (!presContext) { + return NS_ERROR_FAILURE; + } + event.mTouches.SetCapacity(aCount); + for (uint32_t i = 0; i < aCount; ++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]); + + event.mTouches.AppendElement(t); + } + + nsEventStatus status; + if (aToWindow) { + nsCOMPtr<nsIPresShell> presShell; + nsView* view = nsContentUtils::GetViewToDispatchEvent(presContext, getter_AddRefs(presShell)); + if (!presShell || !view) { + return NS_ERROR_FAILURE; + } + status = nsEventStatus_eIgnore; + *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault); + return presShell->HandleEvent(view->GetFrame(), &event, false, &status); + } + + nsresult rv = widget->DispatchEvent(&event, status); + *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault); + return rv; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendKeyEvent(const nsAString& aType, + int32_t aKeyCode, + int32_t aCharCode, + int32_t aModifiers, + uint32_t aAdditionalFlags, + bool* aDefaultActionTaken) +{ + // get the widget to send the event to + nsCOMPtr<nsIWidget> widget = GetWidget(); + + return nsContentUtils::SendKeyEvent(widget, aType, aKeyCode, aCharCode, + aModifiers, aAdditionalFlags, + aDefaultActionTaken); +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout, + int32_t aNativeKeyCode, + int32_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(NewRunnableMethod + <int32_t, int32_t, uint32_t, nsString, nsString, nsIObserver*> + (widget, &nsIWidget::SynthesizeNativeKeyEvent, aNativeKeyboardLayout, + aNativeKeyCode, aModifiers, aCharacters, aUnmodifiedCharacters, aObserver)); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX, + int32_t aScreenY, + int32_t aNativeMessage, + int32_t aModifierFlags, + nsIDOMElement* aElement, + nsIObserver* aObserver) +{ + // get the widget to send the event to + nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement); + if (!widget) + return NS_ERROR_FAILURE; + + NS_DispatchToMainThread(NewRunnableMethod + <LayoutDeviceIntPoint, int32_t, int32_t, nsIObserver*> + (widget, &nsIWidget::SynthesizeNativeMouseEvent, + LayoutDeviceIntPoint(aScreenX, aScreenY), aNativeMessage, aModifierFlags, + aObserver)); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendNativeMouseMove(int32_t aScreenX, + int32_t aScreenY, + nsIDOMElement* aElement, + nsIObserver* aObserver) +{ + // get the widget to send the event to + nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement); + if (!widget) + return NS_ERROR_FAILURE; + + NS_DispatchToMainThread(NewRunnableMethod + <LayoutDeviceIntPoint, nsIObserver*> + (widget, &nsIWidget::SynthesizeNativeMouseMove, + LayoutDeviceIntPoint(aScreenX, aScreenY), 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, + nsIDOMElement* aElement, + nsIObserver* aObserver) +{ + // get the widget to send the event to + nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement); + if (!widget) { + return NS_ERROR_FAILURE; + } + + NS_DispatchToMainThread(NewRunnableMethod + <mozilla::LayoutDeviceIntPoint, uint32_t, double, double, double, uint32_t, uint32_t, nsIObserver*> + (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) +{ + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) { + return NS_ERROR_FAILURE; + } + + if (aPressure < 0 || aPressure > 1 || aOrientation > 359) { + return NS_ERROR_INVALID_ARG; + } + + NS_DispatchToMainThread(NewRunnableMethod + <uint32_t, nsIWidget::TouchPointerState, LayoutDeviceIntPoint, double, uint32_t, nsIObserver*> + (widget, &nsIWidget::SynthesizeNativeTouchPoint, aPointerId, + (nsIWidget::TouchPointerState)aTouchState, + LayoutDeviceIntPoint(aScreenX, aScreenY), + aPressure, aOrientation, aObserver)); + 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(NewRunnableMethod + <LayoutDeviceIntPoint, bool, nsIObserver*> + (widget, &nsIWidget::SynthesizeNativeTouchTap, + LayoutDeviceIntPoint(aScreenX, aScreenY), aLongTap, aObserver)); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::ClearNativeTouchSequence(nsIObserver* aObserver) +{ + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) { + return NS_ERROR_FAILURE; + } + + NS_DispatchToMainThread(NewRunnableMethod<nsIObserver*> + (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) { + nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell(); + return nsContentUtils::GetWidget(presShell, aOffset); + } + } + + return nullptr; +} + +nsIWidget* +nsDOMWindowUtils::GetWidgetForElement(nsIDOMElement* aElement) +{ + if (!aElement) + return GetWidget(); + + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); + nsIDocument* doc = content->GetUncomposedDoc(); + nsIPresShell* presShell = doc ? doc->GetShell() : nullptr; + + if (presShell) { + nsIFrame* frame = content->GetPrimaryFrame(); + if (!frame) { + frame = presShell->GetRootFrame(); + } + if (frame) + return frame->GetNearestWidget(); + } + + return nullptr; +} + +NS_IMETHODIMP +nsDOMWindowUtils::Focus(nsIDOMElement* aElement) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); + if (fm) { + if (aElement) + fm->SetFocus(aElement, 0); + else + fm->ClearFocus(window); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener *aListener, + int32_t aExtraForgetSkippableCalls) +{ + PROFILER_LABEL("nsDOMWindowUtils", "GarbageCollect", + js::ProfileEntry::Category::GC); + + nsJSContext::GarbageCollectNow(JS::gcreason::DOM_UTILS); + nsJSContext::CycleCollectNow(aListener, aExtraForgetSkippableCalls); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener *aListener, + int32_t aExtraForgetSkippableCalls) +{ + nsJSContext::CycleCollectNow(aListener, aExtraForgetSkippableCalls); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::RunNextCollectorTimer() +{ + nsJSContext::RunNextCollectorTimer(); + + 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; + event.mTime = PR_IntervalNow(); + + 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, + nsIDOMElement** aReturn) +{ + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_STATE(doc); + + Element* el = + doc->ElementFromPointHelper(aX, aY, aIgnoreRootScrollFrame, aFlushLayout); + nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el); + retval.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, + nsIDOMNodeList** aReturn) +{ + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_STATE(doc); + + return doc->NodesFromRectHelper(aX, aY, aTopSize, aRightSize, aBottomSize, aLeftSize, + aIgnoreRootScrollFrame, aFlushLayout, aReturn); +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetTranslationNodes(nsIDOMNode* aRoot, + nsITranslationNodeList** aRetVal) +{ + NS_ENSURE_ARG_POINTER(aRetVal); + nsCOMPtr<nsIContent> root = do_QueryInterface(aRoot); + NS_ENSURE_STATE(root); + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_STATE(doc); + + if (root->OwnerDoc() != doc) { + return NS_ERROR_DOM_WRONG_DOCUMENT_ERR; + } + + nsTHashtable<nsPtrHashKey<nsIContent>> translationNodesHash(500); + RefPtr<nsTranslationNodeList> list = new nsTranslationNodeList; + + uint32_t limit = 15000; + + // We begin iteration with content->GetNextNode because we want to explictly + // skip the root tag from being a translation node. + nsIContent* content = root; + while ((limit > 0) && (content = content->GetNextNode(root))) { + if (!content->IsHTMLElement()) { + continue; + } + + // Skip elements that usually contain non-translatable text content. + if (content->IsAnyOfHTMLElements(nsGkAtoms::script, + nsGkAtoms::iframe, + nsGkAtoms::frameset, + nsGkAtoms::frame, + nsGkAtoms::code, + nsGkAtoms::noscript, + nsGkAtoms::style)) { + continue; + } + + // An element is a translation node if it contains + // at least one text node that has meaningful data + // for translation + for (nsIContent* child = content->GetFirstChild(); + child; + child = child->GetNextSibling()) { + + if (child->HasTextForTranslation()) { + translationNodesHash.PutEntry(content); + + bool isBlockFrame = false; + nsIFrame* frame = content->GetPrimaryFrame(); + if (frame) { + isBlockFrame = frame->IsFrameOfType(nsIFrame::eBlockFrame); + } + + bool isTranslationRoot = isBlockFrame; + if (!isBlockFrame) { + // If an element is not a block element, it still + // can be considered a translation root if the parent + // of this element didn't make into the list of nodes + // to be translated. + bool parentInList = false; + nsIContent* parent = content->GetParent(); + if (parent) { + parentInList = translationNodesHash.Contains(parent); + } + isTranslationRoot = !parentInList; + } + + list->AppendElement(content->AsDOMNode(), isTranslationRoot); + --limit; + break; + } + } + } + + *aRetVal = list.forget().take(); + return NS_OK; +} + +static already_AddRefed<DataSourceSurface> +CanvasToDataSourceSurface(nsIDOMHTMLCanvasElement* aCanvas) +{ + nsCOMPtr<nsINode> node = do_QueryInterface(aCanvas); + if (!node) { + return nullptr; + } + + MOZ_ASSERT(node->IsElement(), + "An nsINode that implements nsIDOMHTMLCanvasElement should " + "be an element."); + nsLayoutUtils::SurfaceFromElementResult result = + nsLayoutUtils::SurfaceFromElement(node->AsElement()); + + MOZ_ASSERT(result.GetSourceSurface()); + return result.GetSourceSurface()->GetDataSurface(); +} + +NS_IMETHODIMP +nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1, + nsIDOMHTMLCanvasElement *aCanvas2, + uint32_t* aMaxDifference, + uint32_t* retVal) +{ + if (aCanvas1 == nullptr || + aCanvas2 == nullptr || + retVal == nullptr) + return NS_ERROR_FAILURE; + + RefPtr<DataSourceSurface> img1 = CanvasToDataSourceSurface(aCanvas1); + RefPtr<DataSourceSurface> img2 = CanvasToDataSourceSurface(aCanvas2); + + DataSourceSurface::ScopedMap map1(img1, DataSourceSurface::READ); + DataSourceSurface::ScopedMap map2(img2, DataSourceSurface::READ); + + if (img1 == nullptr || img2 == nullptr || + !map1.IsMapped() || !map2.IsMapped() || + img1->GetSize() != img2->GetSize() || + map1.GetStride() != map2.GetStride()) { + return NS_ERROR_FAILURE; + } + + int v; + IntSize size = img1->GetSize(); + int32_t stride = map1.GetStride(); + + // we can optimize for the common all-pass case + if (stride == size.width * 4) { + v = memcmp(map1.GetData(), map2.GetData(), size.width * size.height * 4); + if (v == 0) { + if (aMaxDifference) + *aMaxDifference = 0; + *retVal = 0; + return NS_OK; + } + } + + uint32_t dc = 0; + uint32_t different = 0; + + for (int j = 0; j < size.height; j++) { + unsigned char *p1 = map1.GetData() + j*stride; + unsigned char *p2 = map2.GetData() + j*stride; + v = memcmp(p1, p2, stride); + + if (v) { + for (int i = 0; i < size.width; i++) { + if (*(uint32_t*) p1 != *(uint32_t*) p2) { + + different++; + + dc = std::max((uint32_t)abs(p1[0] - p2[0]), dc); + dc = std::max((uint32_t)abs(p1[1] - p2[1]), dc); + dc = std::max((uint32_t)abs(p1[2] - p2[2]), dc); + dc = std::max((uint32_t)abs(p1[3] - p2[3]), dc); + } + + p1 += 4; + p2 += 4; + } + } + } + + if (aMaxDifference) + *aMaxDifference = dc; + + *retVal = different; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetIsMozAfterPaintPending(bool *aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = false; + nsPresContext* presContext = GetPresContext(); + if (!presContext) + return NS_OK; + *aResult = presContext->IsDOMPaintEventPending(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::ClearMozAfterPaintEvents() +{ + nsPresContext* presContext = GetPresContext(); + if (!presContext) + return NS_OK; + presContext->ClearMozAfterPaintEvents(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::DisableNonTestMouseEvents(bool aDisable) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + nsIDocShell *docShell = window->GetDocShell(); + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); + nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell(); + NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); + presShell->DisableNonTestMouseEvents(aDisable); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SuppressEventHandling(bool aSuppress) +{ + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); + + if (aSuppress) { + doc->SuppressEventHandling(nsIDocument::eEvents); + } else { + doc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, true); + } + + return NS_OK; +} + +static nsresult +getScrollXYAppUnits(nsWeakPtr aWindow, bool aFlushLayout, nsPoint& aScrollPos) { + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(aWindow); + nsCOMPtr<nsIDocument> doc = window ? window->GetExtantDoc() : nullptr; + NS_ENSURE_STATE(doc); + + if (aFlushLayout) { + doc->FlushPendingNotifications(Flush_Layout); + } + + nsIPresShell *presShell = doc->GetShell(); + if (presShell) { + nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable(); + if (sf) { + aScrollPos = sf->GetScrollPosition(); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX, int32_t* aScrollY) +{ + nsPoint scrollPos(0,0); + nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos); + NS_ENSURE_SUCCESS(rv, rv); + *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x); + *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetScrollXYFloat(bool aFlushLayout, float* aScrollX, float* aScrollY) +{ + nsPoint scrollPos(0,0); + nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos); + NS_ENSURE_SUCCESS(rv, rv); + *aScrollX = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.x); + *aScrollY = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.y); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetScrollbarSize(bool aFlushLayout, int32_t* aWidth, + int32_t* aHeight) +{ + *aWidth = 0; + *aHeight = 0; + + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_STATE(doc); + + if (aFlushLayout) { + doc->FlushPendingNotifications(Flush_Layout); + } + + nsIPresShell* presShell = doc->GetShell(); + NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE); + + nsIScrollableFrame* scrollFrame = presShell->GetRootScrollFrameAsScrollable(); + NS_ENSURE_TRUE(scrollFrame, NS_OK); + + nsMargin sizes = scrollFrame->GetActualScrollbarSizes(); + *aWidth = nsPresContext::AppUnitsToIntCSSPixels(sizes.LeftRight()); + *aHeight = nsPresContext::AppUnitsToIntCSSPixels(sizes.TopBottom()); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetBoundsWithoutFlushing(nsIDOMElement *aElement, + nsIDOMClientRect** aResult) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + nsresult rv; + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + RefPtr<DOMRect> rect = new DOMRect(window); + nsIFrame* frame = content->GetPrimaryFrame(); + + if (frame) { + nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame, + nsLayoutUtils::GetContainingBlockForClientRect(frame), + nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + rect->SetLayoutRect(r); + } + + rect.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetRootBounds(nsIDOMClientRect** aResult) +{ + nsIDocument* doc = GetDocument(); + NS_ENSURE_STATE(doc); + + nsRect bounds(0, 0, 0, 0); + nsIPresShell* presShell = doc->GetShell(); + if (presShell) { + nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable(); + if (sf) { + bounds = sf->GetScrollRange(); + bounds.width += sf->GetScrollPortRect().width; + bounds.height += sf->GetScrollPortRect().height; + } else if (presShell->GetRootFrame()) { + bounds = presShell->GetRootFrame()->GetRect(); + } + } + + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + RefPtr<DOMRect> rect = new DOMRect(window); + rect->SetRect(nsPresContext::AppUnitsToFloatCSSPixels(bounds.x), + nsPresContext::AppUnitsToFloatCSSPixels(bounds.y), + nsPresContext::AppUnitsToFloatCSSPixels(bounds.width), + nsPresContext::AppUnitsToFloatCSSPixels(bounds.height)); + rect.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetIMEIsOpen(bool *aState) +{ + NS_ENSURE_ARG_POINTER(aState); + + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + // Open state should not be available when IME is not enabled. + InputContext context = widget->GetInputContext(); + if (context.mIMEState.mEnabled != IMEState::ENABLED) { + return NS_ERROR_NOT_AVAILABLE; + } + + if (context.mIMEState.mOpen == IMEState::OPEN_STATE_NOT_SUPPORTED) { + return NS_ERROR_NOT_IMPLEMENTED; + } + *aState = (context.mIMEState.mOpen == IMEState::OPEN); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetIMEStatus(uint32_t *aState) +{ + NS_ENSURE_ARG_POINTER(aState); + + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + InputContext context = widget->GetInputContext(); + *aState = static_cast<uint32_t>(context.mIMEState.mEnabled); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetFocusedInputType(char** aType) +{ + NS_ENSURE_ARG_POINTER(aType); + + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) { + return NS_ERROR_FAILURE; + } + + InputContext context = widget->GetInputContext(); + *aType = ToNewCString(context.mHTMLInputType); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetViewId(nsIDOMElement* aElement, nsViewID* aResult) +{ + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); + if (content && nsLayoutUtils::FindIDFor(content, aResult)) { + return NS_OK; + } + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetScreenPixelsPerCSSPixel(float* aScreenPixels) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + *aScreenPixels = window->GetDevicePixelRatio(CallerType::System); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetFullZoom(float* aFullZoom) +{ + *aFullZoom = 1.0f; + + nsPresContext* presContext = GetPresContext(); + if (!presContext) { + return NS_OK; + } + + *aFullZoom = presContext->DeviceContext()->GetFullZoom(); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::DispatchDOMEventViaPresShell(nsIDOMNode* aTarget, + nsIDOMEvent* aEvent, + bool aTrusted, + bool* aRetVal) +{ + NS_ENSURE_STATE(aEvent); + aEvent->SetTrusted(aTrusted); + WidgetEvent* internalEvent = aEvent->WidgetEventPtr(); + NS_ENSURE_STATE(internalEvent); + nsCOMPtr<nsIContent> content = do_QueryInterface(aTarget); + NS_ENSURE_STATE(content); + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + if (content->OwnerDoc()->GetWindow() != window) { + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; + } + nsCOMPtr<nsIDocument> targetDoc = content->GetUncomposedDoc(); + NS_ENSURE_STATE(targetDoc); + RefPtr<nsIPresShell> targetShell = targetDoc->GetShell(); + NS_ENSURE_STATE(targetShell); + + targetDoc->FlushPendingNotifications(Flush_Layout); + + nsEventStatus status = nsEventStatus_eIgnore; + targetShell->HandleEventWithTarget(internalEvent, nullptr, content, &status); + *aRetVal = (status != nsEventStatus_eConsumeNoDefault); + return NS_OK; +} + +static void +InitEvent(WidgetGUIEvent& aEvent, LayoutDeviceIntPoint* aPt = nullptr) +{ + if (aPt) { + aEvent.mRefPoint = *aPt; + } + aEvent.mTime = PR_IntervalNow(); +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType, + int64_t aOffset, uint32_t aLength, + int32_t aX, int32_t aY, + uint32_t aAdditionalFlags, + nsIQueryContentEventResult **aResult) +{ + *aResult = nullptr; + + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + nsIDocShell *docShell = window->GetDocShell(); + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); + + nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell(); + NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); + + nsPresContext* presContext = presShell->GetPresContext(); + NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); + + // get the widget to send the event to + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) { + return NS_ERROR_FAILURE; + } + + EventMessage message; + switch (aType) { + case QUERY_SELECTED_TEXT: + message = eQuerySelectedText; + break; + case QUERY_TEXT_CONTENT: + message = eQueryTextContent; + break; + case QUERY_CARET_RECT: + message = eQueryCaretRect; + break; + case QUERY_TEXT_RECT: + message = eQueryTextRect; + break; + case QUERY_EDITOR_RECT: + message = eQueryEditorRect; + break; + case QUERY_CHARACTER_AT_POINT: + message = eQueryCharacterAtPoint; + break; + case QUERY_TEXT_RECT_ARRAY: + message = eQueryTextRectArray; + break; + default: + return NS_ERROR_INVALID_ARG; + } + + SelectionType selectionType = SelectionType::eNormal; + static const uint32_t kSelectionFlags = + QUERY_CONTENT_FLAG_SELECTION_SPELLCHECK | + QUERY_CONTENT_FLAG_SELECTION_IME_RAWINPUT | + QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDRAWTEXT | + QUERY_CONTENT_FLAG_SELECTION_IME_CONVERTEDTEXT | + QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDCONVERTEDTEXT | + QUERY_CONTENT_FLAG_SELECTION_ACCESSIBILITY | + QUERY_CONTENT_FLAG_SELECTION_FIND | + QUERY_CONTENT_FLAG_SELECTION_URLSECONDARY | + QUERY_CONTENT_FLAG_SELECTION_URLSTRIKEOUT; + switch (aAdditionalFlags & kSelectionFlags) { + case QUERY_CONTENT_FLAG_SELECTION_SPELLCHECK: + selectionType = SelectionType::eSpellCheck; + break; + case QUERY_CONTENT_FLAG_SELECTION_IME_RAWINPUT: + selectionType = SelectionType::eIMERawClause; + break; + case QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDRAWTEXT: + selectionType = SelectionType::eIMESelectedRawClause; + break; + case QUERY_CONTENT_FLAG_SELECTION_IME_CONVERTEDTEXT: + selectionType = SelectionType::eIMEConvertedClause; + break; + case QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDCONVERTEDTEXT: + selectionType = SelectionType::eIMESelectedClause; + break; + case QUERY_CONTENT_FLAG_SELECTION_ACCESSIBILITY: + selectionType = SelectionType::eAccessibility; + break; + case QUERY_CONTENT_FLAG_SELECTION_FIND: + selectionType = SelectionType::eFind; + break; + case QUERY_CONTENT_FLAG_SELECTION_URLSECONDARY: + selectionType = SelectionType::eURLSecondary; + break; + case QUERY_CONTENT_FLAG_SELECTION_URLSTRIKEOUT: + selectionType = SelectionType::eURLStrikeout; + break; + case 0: + break; + default: + return NS_ERROR_INVALID_ARG; + } + + if (selectionType != SelectionType::eNormal && + message != eQuerySelectedText) { + return NS_ERROR_INVALID_ARG; + } + + nsCOMPtr<nsIWidget> targetWidget = widget; + LayoutDeviceIntPoint pt(aX, aY); + + WidgetQueryContentEvent::Options options; + options.mUseNativeLineBreak = + !(aAdditionalFlags & QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK); + options.mRelativeToInsertionPoint = + (aAdditionalFlags & + QUERY_CONTENT_FLAG_OFFSET_RELATIVE_TO_INSERTION_POINT) != 0; + if (options.mRelativeToInsertionPoint) { + switch (message) { + case eQueryTextContent: + case eQueryCaretRect: + case eQueryTextRect: + break; + default: + return NS_ERROR_INVALID_ARG; + } + } else if (aOffset < 0) { + return NS_ERROR_INVALID_ARG; + } + + if (message == eQueryCharacterAtPoint) { + // Looking for the widget at the point. + WidgetQueryContentEvent dummyEvent(true, eQueryContentState, widget); + dummyEvent.Init(options); + InitEvent(dummyEvent, &pt); + nsIFrame* popupFrame = + nsLayoutUtils::GetPopupFrameForEventCoordinates(presContext->GetRootPresContext(), &dummyEvent); + + LayoutDeviceIntRect widgetBounds = widget->GetClientBounds(); + widgetBounds.MoveTo(0, 0); + + // There is no popup frame at the point and the point isn't in our widget, + // we cannot process this request. + NS_ENSURE_TRUE(popupFrame || widgetBounds.Contains(pt), NS_ERROR_FAILURE); + + // Fire the event on the widget at the point + if (popupFrame) { + targetWidget = popupFrame->GetNearestWidget(); + } + } + + pt += widget->WidgetToScreenOffset() - targetWidget->WidgetToScreenOffset(); + + WidgetQueryContentEvent queryEvent(true, message, targetWidget); + InitEvent(queryEvent, &pt); + + switch (message) { + case eQueryTextContent: + queryEvent.InitForQueryTextContent(aOffset, aLength, options); + break; + case eQueryCaretRect: + queryEvent.InitForQueryCaretRect(aOffset, options); + break; + case eQueryTextRect: + queryEvent.InitForQueryTextRect(aOffset, aLength, options); + break; + case eQuerySelectedText: + queryEvent.InitForQuerySelectedText(selectionType, options); + break; + case eQueryTextRectArray: + queryEvent.InitForQueryTextRectArray(aOffset, aLength, options); + break; + default: + queryEvent.Init(options); + break; + } + + nsEventStatus status; + nsresult rv = targetWidget->DispatchEvent(&queryEvent, status); + NS_ENSURE_SUCCESS(rv, rv); + + nsQueryContentEventResult* result = new nsQueryContentEventResult(); + result->SetEventResult(widget, queryEvent); + NS_ADDREF(*aResult = result); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendSelectionSetEvent(uint32_t aOffset, + uint32_t aLength, + uint32_t aAdditionalFlags, + bool *aResult) +{ + *aResult = false; + + // get the widget to send the event to + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) { + return NS_ERROR_FAILURE; + } + + WidgetSelectionEvent selectionEvent(true, eSetSelection, widget); + InitEvent(selectionEvent); + + selectionEvent.mOffset = aOffset; + selectionEvent.mLength = aLength; + selectionEvent.mReversed = (aAdditionalFlags & SELECTION_SET_FLAG_REVERSE); + selectionEvent.mUseNativeLineBreak = + !(aAdditionalFlags & SELECTION_SET_FLAG_USE_XP_LINE_BREAK); + + nsEventStatus status; + nsresult rv = widget->DispatchEvent(&selectionEvent, status); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = selectionEvent.mSucceeded; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SendContentCommandEvent(const nsAString& aType, + nsITransferable * aTransferable) +{ + // get the widget to send the event to + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + EventMessage msg; + if (aType.EqualsLiteral("cut")) { + msg = eContentCommandCut; + } else if (aType.EqualsLiteral("copy")) { + msg = eContentCommandCopy; + } else if (aType.EqualsLiteral("paste")) { + msg = eContentCommandPaste; + } else if (aType.EqualsLiteral("delete")) { + msg = eContentCommandDelete; + } else if (aType.EqualsLiteral("undo")) { + msg = eContentCommandUndo; + } else if (aType.EqualsLiteral("redo")) { + msg = eContentCommandRedo; + } else if (aType.EqualsLiteral("pasteTransferable")) { + msg = eContentCommandPasteTransferable; + } else { + return NS_ERROR_FAILURE; + } + + WidgetContentCommandEvent event(true, msg, widget); + if (msg == eContentCommandPasteTransferable) { + event.mTransferable = aTransferable; + } + + nsEventStatus status; + return widget->DispatchEvent(&event, status); +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetClassName(JS::Handle<JS::Value> aObject, JSContext* aCx, + char** aName) +{ + // Our argument must be a non-null object. + if (aObject.isPrimitive()) { + return NS_ERROR_XPC_BAD_CONVERT_JS; + } + + *aName = NS_strdup(JS_GetClass(aObject.toObjectOrNull())->name); + MOZ_ASSERT(*aName, "NS_strdup should be infallible."); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetVisitedDependentComputedStyle( + nsIDOMElement *aElement, const nsAString& aPseudoElement, + const nsAString& aPropertyName, nsAString& aResult) +{ + aResult.Truncate(); + + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + nsCOMPtr<Element> element = do_QueryInterface(aElement); + NS_ENSURE_STATE(window && element); + nsCOMPtr<nsPIDOMWindowInner> innerWindow = window->GetCurrentInnerWindow(); + NS_ENSURE_STATE(window); + + nsCOMPtr<nsIDOMCSSStyleDeclaration> decl; + { + ErrorResult rv; + decl = innerWindow->GetComputedStyle(*element, aPseudoElement, rv); + ENSURE_SUCCESS(rv, rv.StealNSResult()); + } + + static_cast<nsComputedDOMStyle*>(decl.get())->SetExposeVisitedStyle(true); + nsresult rv = decl->GetPropertyValue(aPropertyName, aResult); + static_cast<nsComputedDOMStyle*>(decl.get())->SetExposeVisitedStyle(false); + + return rv; +} + +NS_IMETHODIMP +nsDOMWindowUtils::EnterModalState() +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + window->EnterModalState(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::LeaveModalState() +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + window->LeaveModalState(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::IsInModalState(bool *retval) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + *retval = nsGlobalWindow::Cast(window)->IsInModalState(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetDesktopModeViewport(bool aDesktopMode) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + window->SetDesktopModeViewport(aDesktopMode); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetOuterWindowID(uint64_t *aWindowID) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + NS_ASSERTION(window->IsOuterWindow(), "How did that happen?"); + *aWindowID = window->WindowID(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetCurrentInnerWindowID(uint64_t *aWindowID) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE); + + NS_ASSERTION(window->IsOuterWindow(), "How did that happen?"); + nsGlobalWindow* inner = + nsGlobalWindow::Cast(window)->GetCurrentInnerWindowInternal(); + if (!inner) { + return NS_ERROR_NOT_AVAILABLE; + } + *aWindowID = inner->WindowID(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SuspendTimeouts() +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow(); + NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE); + + inner->Suspend(); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::ResumeTimeouts() +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow(); + NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE); + + inner->Resume(); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetLayerManagerType(nsAString& aType) +{ + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + LayerManager *mgr = widget->GetLayerManager(nsIWidget::LAYER_MANAGER_PERSISTENT); + if (!mgr) + return NS_ERROR_FAILURE; + + mgr->GetBackendName(aType); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetLayerManagerRemote(bool* retval) +{ + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + LayerManager *mgr = widget->GetLayerManager(); + if (!mgr) + return NS_ERROR_FAILURE; + + *retval = !!mgr->AsShadowForwarder(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetSupportsHardwareH264Decoding(JS::MutableHandle<JS::Value> aPromise) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + nsCOMPtr<nsIGlobalObject> parentObject = + do_QueryInterface(window->GetCurrentInnerWindow()); + NS_ENSURE_STATE(parentObject); +#ifdef MOZ_FMP4 + nsCOMPtr<nsIWidget> widget = GetWidget(); + NS_ENSURE_STATE(widget); + LayerManager *mgr = widget->GetLayerManager(); + NS_ENSURE_STATE(mgr); + RefPtr<Promise> promise = + MP4Decoder::IsVideoAccelerated(mgr->AsShadowForwarder(), parentObject); + NS_ENSURE_STATE(promise); + aPromise.setObject(*promise->PromiseObj()); +#else + ErrorResult rv; + RefPtr<Promise> promise = Promise::Create(parentObject, rv); + if (rv.Failed()) { + return rv.StealNSResult(); + } + promise->MaybeResolve(NS_LITERAL_STRING("No; Compiled without MP4 support.")); + aPromise.setObject(*promise->PromiseObj()); +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetCurrentAudioBackend(nsAString& aBackend) +{ + CubebUtils::GetCurrentBackend(aBackend); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::StartFrameTimeRecording(uint32_t *startIndex) +{ + NS_ENSURE_ARG_POINTER(startIndex); + + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + LayerManager *mgr = widget->GetLayerManager(); + if (!mgr) + return NS_ERROR_FAILURE; + + const uint32_t kRecordingMinSize = 60 * 10; // 10 seconds @60 fps. + const uint32_t kRecordingMaxSize = 60 * 60 * 60; // One hour + uint32_t bufferSize = Preferences::GetUint("toolkit.framesRecording.bufferSize", uint32_t(0)); + bufferSize = std::min(bufferSize, kRecordingMaxSize); + bufferSize = std::max(bufferSize, kRecordingMinSize); + *startIndex = mgr->StartFrameTimeRecording(bufferSize); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::StopFrameTimeRecording(uint32_t startIndex, + uint32_t *frameCount, + float **frameIntervals) +{ + NS_ENSURE_ARG_POINTER(frameCount); + NS_ENSURE_ARG_POINTER(frameIntervals); + + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + LayerManager *mgr = widget->GetLayerManager(); + if (!mgr) + return NS_ERROR_FAILURE; + + nsTArray<float> tmpFrameIntervals; + mgr->StopFrameTimeRecording(startIndex, tmpFrameIntervals); + *frameCount = tmpFrameIntervals.Length(); + + *frameIntervals = (float*)moz_xmalloc(*frameCount * sizeof(float)); + + /* copy over the frame intervals and paint times into the arrays we just allocated */ + for (uint32_t i = 0; i < *frameCount; i++) { + (*frameIntervals)[i] = tmpFrameIntervals[i]; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::BeginTabSwitch() +{ + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + LayerManager *mgr = widget->GetLayerManager(); + if (!mgr) + return NS_ERROR_FAILURE; + + mgr->BeginTabSwitch(); + + return NS_OK; +} + +static bool +ComputeAnimationValue(nsCSSPropertyID aProperty, + Element* aElement, + const nsAString& aInput, + StyleAnimationValue& aOutput) +{ + nsIDocument* doc = aElement->GetUncomposedDoc(); + nsIPresShell* shell = doc->GetShell(); + if (!shell) { + return false; + } + + RefPtr<nsStyleContext> styleContext = + nsComputedDOMStyle::GetStyleContextForElement(aElement, nullptr, shell); + + if (!StyleAnimationValue::ComputeValue(aProperty, aElement, styleContext, + aInput, false, aOutput)) { + return false; + } + return true; +} + +NS_IMETHODIMP +nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds) +{ + // Before we advance the time, we should trigger any animations that are + // waiting to start. This is because there are many tests that call this + // which expect animations to start immediately. Ideally, we should make + // all these tests do an asynchronous wait on the corresponding animation's + // 'ready' promise before continuing. Then we could remove the special + // handling here and the code path followed when testing would more closely + // match the code path during regular operation. Filed as bug 1112957. + nsCOMPtr<nsIDocument> doc = GetDocument(); + if (doc) { + PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker(); + if (tracker) { + tracker->TriggerPendingAnimationsNow(); + } + } + + nsPresContext* presContext = GetPresContext(); + if (presContext) { + nsRefreshDriver* driver = presContext->RefreshDriver(); + driver->AdvanceTimeAndRefresh(aMilliseconds); + + RefPtr<LayerTransactionChild> transaction = GetLayerTransaction(); + if (transaction && transaction->IPCOpen()) { + transaction->SendSetTestSampleTime(driver->MostRecentRefresh()); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetLastTransactionId(uint64_t *aLastTransactionId) +{ + nsPresContext* presContext = GetPresContext(); + if (!presContext) { + return NS_ERROR_UNEXPECTED; + } + + nsRefreshDriver* driver = presContext->GetRootPresContext()->RefreshDriver(); + *aLastTransactionId = driver->LastTransactionId(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::RestoreNormalRefresh() +{ + // Kick the compositor out of test mode before the refresh driver, so that + // the refresh driver doesn't send an update that gets ignored by the + // compositor. + RefPtr<LayerTransactionChild> transaction = GetLayerTransaction(); + if (transaction && transaction->IPCOpen()) { + transaction->SendLeaveTestMode(); + } + + if (nsPresContext* pc = GetPresContext()) { + nsRefreshDriver* driver = pc->RefreshDriver(); + driver->RestoreNormalRefresh(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetIsTestControllingRefreshes(bool *aResult) +{ + nsPresContext* pc = GetPresContext(); + *aResult = + pc ? pc->RefreshDriver()->IsTestControllingRefreshesEnabled() : false; + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetAsyncPanZoomEnabled(bool *aResult) +{ + nsIWidget* widget = GetWidget(); + if (widget) { + *aResult = widget->AsyncPanZoomEnabled(); + } else { + *aResult = gfxPlatform::AsyncPanZoomEnabled(); + } + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetAsyncScrollOffset(nsIDOMNode* aNode, + float aX, float aY) +{ + nsCOMPtr<Element> element = do_QueryInterface(aNode); + if (!element) { + return NS_ERROR_INVALID_ARG; + } + FrameMetrics::ViewID viewId; + if (!nsLayoutUtils::FindIDFor(element, &viewId)) { + return NS_ERROR_UNEXPECTED; + } + nsIWidget* widget = GetWidget(); + if (!widget) { + return NS_ERROR_FAILURE; + } + LayerManager* manager = widget->GetLayerManager(); + if (!manager) { + return NS_ERROR_FAILURE; + } + ShadowLayerForwarder* forwarder = manager->AsShadowForwarder(); + if (!forwarder || !forwarder->HasShadowManager()) { + return NS_ERROR_UNEXPECTED; + } + forwarder->GetShadowManager()->SendSetAsyncScrollOffset(viewId, aX, aY); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetAsyncZoom(nsIDOMNode* aRootElement, float aValue) +{ + nsCOMPtr<Element> element = do_QueryInterface(aRootElement); + if (!element) { + return NS_ERROR_INVALID_ARG; + } + FrameMetrics::ViewID viewId; + if (!nsLayoutUtils::FindIDFor(element, &viewId)) { + return NS_ERROR_UNEXPECTED; + } + nsIWidget* widget = GetWidget(); + if (!widget) { + return NS_ERROR_FAILURE; + } + LayerManager* manager = widget->GetLayerManager(); + if (!manager) { + return NS_ERROR_FAILURE; + } + ShadowLayerForwarder* forwarder = manager->AsShadowForwarder(); + if (!forwarder || !forwarder->HasShadowManager()) { + return NS_ERROR_UNEXPECTED; + } + forwarder->GetShadowManager()->SendSetAsyncZoom(viewId, aValue); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::FlushApzRepaints(bool* aOutResult) +{ + nsIWidget* widget = GetWidget(); + if (!widget) { + *aOutResult = false; + return NS_OK; + } + // If APZ is not enabled, this function is a no-op. + if (!widget->AsyncPanZoomEnabled()) { + *aOutResult = false; + return NS_OK; + } + LayerManager* manager = widget->GetLayerManager(); + if (!manager) { + *aOutResult = false; + return NS_OK; + } + ShadowLayerForwarder* forwarder = manager->AsShadowForwarder(); + if (!forwarder || !forwarder->HasShadowManager()) { + *aOutResult = false; + return NS_OK; + } + forwarder->GetShadowManager()->SendFlushApzRepaints(); + *aOutResult = true; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::ZoomToFocusedInput() +{ + nsIWidget* widget = GetWidget(); + if (!widget) { + return NS_OK; + } + // If APZ is not enabled, this function is a no-op. + if (!widget->AsyncPanZoomEnabled()) { + return NS_OK; + } + + nsFocusManager* fm = nsFocusManager::GetFocusManager(); + if (!fm) { + return NS_OK; + } + + nsIContent* content = fm->GetFocusedContent(); + if (!content) { + return NS_OK; + } + + nsIPresShell* shell = APZCCallbackHelper::GetRootContentDocumentPresShellForContent(content); + if (!shell) { + return NS_OK; + } + + nsIScrollableFrame* rootScrollFrame = shell->GetRootScrollFrameAsScrollable(); + if (!rootScrollFrame) { + return NS_OK; + } + + nsIDocument* document = shell->GetDocument(); + if (!document) { + return NS_OK; + } + + uint32_t presShellId; + FrameMetrics::ViewID viewId; + if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(document->GetDocumentElement(), &presShellId, &viewId)) { + uint32_t flags = layers::DISABLE_ZOOM_OUT; + if (!Preferences::GetBool("formhelper.autozoom")) { + flags |= layers::PAN_INTO_VIEW_ONLY; + } else { + flags |= layers::ONLY_ZOOM_TO_DEFAULT_SCALE; + } + + CSSRect bounds = nsLayoutUtils::GetBoundingContentRect(content, rootScrollFrame); + if (bounds.IsEmpty()) { + // Do not zoom on empty bounds. Bail out. + return NS_OK; + } + bounds.Inflate(15.0f, 0.0f); + widget->ZoomToRect(presShellId, viewId, bounds, flags); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::ComputeAnimationDistance(nsIDOMElement* aElement, + const nsAString& aProperty, + const nsAString& aValue1, + const nsAString& aValue2, + double* aResult) +{ + nsresult rv; + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCSSPropertyID property = + nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eIgnoreEnabledState); + if (property != eCSSProperty_UNKNOWN && nsCSSProps::IsShorthand(property)) { + property = eCSSProperty_UNKNOWN; + } + + MOZ_ASSERT(property == eCSSProperty_UNKNOWN || + !nsCSSProps::IsShorthand(property), + "should not have shorthand"); + + StyleAnimationValue v1, v2; + Element* element = content->AsElement(); + if (property == eCSSProperty_UNKNOWN || + !ComputeAnimationValue(property, element, aValue1, v1) || + !ComputeAnimationValue(property, element, aValue2, v2)) { + return NS_ERROR_ILLEGAL_VALUE; + } + + nsIPresShell* shell = element->GetUncomposedDoc()->GetShell(); + RefPtr<nsStyleContext> styleContext = shell + ? nsComputedDOMStyle::GetStyleContextForElement(element, nullptr, shell) + : nullptr; + if (!StyleAnimationValue::ComputeDistance(property, v1, v2, styleContext, + *aResult)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +nsDOMWindowUtils::RenderDocument(const nsRect& aRect, + uint32_t aFlags, + nscolor aBackgroundColor, + gfxContext* aThebesContext) +{ + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); + + // Get Primary Shell + nsCOMPtr<nsIPresShell> presShell = doc->GetShell(); + NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); + + // Render Document + return presShell->RenderDocument(aRect, aFlags, aBackgroundColor, aThebesContext); +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetCursorType(int16_t *aCursor) +{ + NS_ENSURE_ARG_POINTER(aCursor); + + nsIDocument* doc = GetDocument(); + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); + + bool isSameDoc = false; + do { + if (EventStateManager::sMouseOverDocument == doc) { + isSameDoc = true; + break; + } + } while ((doc = doc->GetParentDocument())); + + if (!isSameDoc) { + *aCursor = eCursor_none; + return NS_OK; + } + + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + // fetch cursor value from window's widget + *aCursor = widget->GetCursor(); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetDisplayDPI(float *aDPI) +{ + nsCOMPtr<nsIWidget> widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + *aDPI = widget->GetDPI(); + + return NS_OK; +} + + +NS_IMETHODIMP +nsDOMWindowUtils::GetOuterWindowWithId(uint64_t aWindowID, + nsIDOMWindow** aWindow) +{ + // XXX This method is deprecated. See bug 865664. + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + NS_LITERAL_CSTRING("DOM"), + nsContentUtils::GetDocumentFromCaller(), + nsContentUtils::eDOM_PROPERTIES, + "GetWindowWithOuterIdWarning"); + + *aWindow = nsGlobalWindow::GetOuterWindowWithId(aWindowID); + NS_IF_ADDREF(*aWindow); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetContainerElement(nsIDOMElement** aResult) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + nsCOMPtr<nsIDOMElement> element = + do_QueryInterface(window->GetFrameElementInternal()); + + element.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile, + nsISupports **aDOMFile) +{ + if (!aFile) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + nsPIDOMWindowInner* innerWindow = window->GetCurrentInnerWindow(); + if (!innerWindow) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsIDOMBlob> blob = File::CreateFromFile(innerWindow, aFile); + blob.forget(aDOMFile); + return NS_OK; +} + +#ifdef DEBUG +static bool +CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredRegion) +{ + gfx::Matrix transform; + if (!aLayer->GetTransform().Is2D(&transform) || + transform.HasNonIntegerTranslation()) + return false; + transform.NudgeToIntegers(); + IntPoint offset = aOffset + IntPoint::Truncate(transform._31, transform._32); + + Layer* child = aLayer->GetFirstChild(); + if (child) { + while (child) { + if (!CheckLeafLayers(child, offset, aCoveredRegion)) + return false; + child = child->GetNextSibling(); + } + } else { + nsIntRegion rgn = aLayer->GetVisibleRegion().ToUnknownRegion(); + rgn.MoveBy(offset); + nsIntRegion tmp; + tmp.And(rgn, *aCoveredRegion); + if (!tmp.IsEmpty()) + return false; + aCoveredRegion->Or(*aCoveredRegion, rgn); + } + + return true; +} +#endif + +NS_IMETHODIMP +nsDOMWindowUtils::LeafLayersPartitionWindow(bool* aResult) +{ + *aResult = true; +#ifdef DEBUG + nsIWidget* widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + LayerManager* manager = widget->GetLayerManager(); + if (!manager) + return NS_ERROR_FAILURE; + nsPresContext* presContext = GetPresContext(); + if (!presContext) + return NS_ERROR_FAILURE; + Layer* root = manager->GetRoot(); + if (!root) + return NS_ERROR_FAILURE; + + nsIntPoint offset(0, 0); + nsIntRegion coveredRegion; + if (!CheckLeafLayers(root, offset, &coveredRegion)) { + *aResult = false; + } + if (!coveredRegion.IsEqual(root->GetVisibleRegion().ToUnknownRegion())) { + *aResult = false; + } +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::CheckAndClearPaintedState(nsIDOMElement* aElement, bool* aResult) +{ + if (!aElement) { + return NS_ERROR_INVALID_ARG; + } + + nsresult rv; + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsIFrame* frame = content->GetPrimaryFrame(); + + if (!frame) { + *aResult = false; + return NS_OK; + } + + // Get the outermost frame for the content node, so that we can test + // canvasframe invalidations by observing the documentElement. + for (;;) { + nsIFrame* parentFrame = frame->GetParent(); + if (parentFrame && parentFrame->GetContent() == content) { + frame = parentFrame; + } else { + break; + } + } + + *aResult = frame->CheckAndClearPaintedState(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::IsPartOfOpaqueLayer(nsIDOMElement* aElement, bool* aResult) +{ + if (!aElement) { + return NS_ERROR_INVALID_ARG; + } + + nsresult rv; + nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsIFrame* frame = content->GetPrimaryFrame(); + if (!frame) { + return NS_ERROR_FAILURE; + } + + PaintedLayer* layer = FrameLayerBuilder::GetDebugSingleOldPaintedLayerForFrame(frame); + if (!layer) { + return NS_ERROR_FAILURE; + } + + *aResult = (layer->GetContentFlags() & Layer::CONTENT_OPAQUE); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::NumberOfAssignedPaintedLayers(nsIDOMElement** aElements, + uint32_t aCount, + uint32_t* aResult) +{ + if (!aElements) { + return NS_ERROR_INVALID_ARG; + } + + nsTHashtable<nsPtrHashKey<PaintedLayer>> layers; + nsresult rv; + for (uint32_t i = 0; i < aCount; i++) { + nsCOMPtr<nsIContent> content = do_QueryInterface(aElements[i], &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsIFrame* frame = content->GetPrimaryFrame(); + if (!frame) { + return NS_ERROR_FAILURE; + } + + PaintedLayer* layer = FrameLayerBuilder::GetDebugSingleOldPaintedLayerForFrame(frame); + if (!layer) { + return NS_ERROR_FAILURE; + } + + layers.PutEntry(layer); + } + + *aResult = layers.Count(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::EnableDialogs() +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + nsGlobalWindow::Cast(window)->EnableDialogs(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::DisableDialogs() +{ + if (!nsContentUtils::IsCallerChrome()) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + nsGlobalWindow::Cast(window)->DisableDialogs(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::AreDialogsEnabled(bool* aResult) +{ + if (!nsContentUtils::IsCallerChrome()) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + *aResult = nsGlobalWindow::Cast(window)->AreDialogsEnabled(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx, + int64_t* _retval) +{ + if (aFile.isPrimitive()) { + *_retval = -1; + return NS_OK; + } + + JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull()); + + IDBMutableFile* mutableFile = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, &obj, mutableFile))) { + *_retval = mutableFile->GetFileId(); + return NS_OK; + } + + Blob* blob = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) { + *_retval = blob->GetFileId(); + return NS_OK; + } + + *_retval = -1; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetFilePath(JS::HandleValue aFile, JSContext* aCx, + nsAString& _retval) +{ + if (aFile.isPrimitive()) { + _retval.Truncate(); + return NS_OK; + } + + JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull()); + + File* file = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(File, &obj, file))) { + nsString filePath; + ErrorResult rv; + file->GetMozFullPathInternal(filePath, rv); + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } + + _retval = filePath; + return NS_OK; + } + + _retval.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId, + JS::Handle<JS::Value> aOptions, + int32_t* aRefCnt, int32_t* aDBRefCnt, + int32_t* aSliceRefCnt, JSContext* aCx, + bool* aResult) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + nsCString origin; + nsresult rv = + quota::QuotaManager::GetInfoFromWindow(window, nullptr, nullptr, &origin, + nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + IDBOpenDBOptions options; + JS::Rooted<JS::Value> optionsVal(aCx, aOptions); + if (!options.Init(aCx, optionsVal)) { + return NS_ERROR_TYPE_ERR; + } + + quota::PersistenceType persistenceType = + quota::PersistenceTypeFromStorage(options.mStorage); + + RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get(); + + if (mgr) { + rv = mgr->BlockAndGetFileReferences(persistenceType, origin, aDatabaseName, + aId, aRefCnt, aDBRefCnt, aSliceRefCnt, + aResult); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + *aRefCnt = *aDBRefCnt = *aSliceRefCnt = -1; + *aResult = false; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::FlushPendingFileDeletions() +{ + RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get(); + if (mgr) { + nsresult rv = mgr->FlushPendingFileDeletions(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::IsIncrementalGCEnabled(JSContext* cx, bool* aResult) +{ + *aResult = JS::IsIncrementalGCEnabled(cx); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::StartPCCountProfiling(JSContext* cx) +{ + js::StartPCCountProfiling(cx); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::StopPCCountProfiling(JSContext* cx) +{ + js::StopPCCountProfiling(cx); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::PurgePCCounts(JSContext* cx) +{ + js::PurgePCCounts(cx); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetPCCountScriptCount(JSContext* cx, int32_t *result) +{ + *result = js::GetPCCountScriptCount(cx); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetPCCountScriptSummary(int32_t script, JSContext* cx, nsAString& result) +{ + JSString *text = js::GetPCCountScriptSummary(cx, script); + if (!text) + return NS_ERROR_FAILURE; + + if (!AssignJSString(cx, result, text)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetPCCountScriptContents(int32_t script, JSContext* cx, nsAString& result) +{ + JSString *text = js::GetPCCountScriptContents(cx, script); + if (!text) + return NS_ERROR_FAILURE; + + if (!AssignJSString(cx, result, text)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetPaintingSuppressed(bool *aPaintingSuppressed) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + nsIDocShell *docShell = window->GetDocShell(); + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); + + nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell(); + NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); + + *aPaintingSuppressed = presShell->IsPaintingSuppressed(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetPlugins(JSContext* cx, JS::MutableHandle<JS::Value> aPlugins) +{ + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_STATE(doc); + + nsTArray<nsIObjectLoadingContent*> plugins; + doc->GetPlugins(plugins); + + JS::Rooted<JSObject*> jsPlugins(cx); + nsresult rv = nsTArrayToJSArray(cx, plugins, &jsPlugins); + NS_ENSURE_SUCCESS(rv, rv); + + aPlugins.setObject(*jsPlugins); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetScrollPositionClampingScrollPortSize(float aWidth, float aHeight) +{ + if (!(aWidth >= 0.0 && aHeight >= 0.0)) { + return NS_ERROR_ILLEGAL_VALUE; + } + + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + nsLayoutUtils::SetScrollPositionClampingScrollPortSize(presShell, CSSSize(aWidth, aHeight)); + + return NS_OK; +} + +nsresult +nsDOMWindowUtils::RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement) +{ + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_STATE(doc); + + doc->RemoteFrameFullscreenChanged(aFrameElement); + return NS_OK; +} + +nsresult +nsDOMWindowUtils::RemoteFrameFullscreenReverted() +{ + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_STATE(doc); + + doc->RemoteFrameFullscreenReverted(); + return NS_OK; +} + +static void +PrepareForFullscreenChange(nsIPresShell* aPresShell, const nsSize& aSize, + nsSize* aOldSize = nullptr) +{ + if (!aPresShell) { + return; + } + if (nsRefreshDriver* rd = aPresShell->GetRefreshDriver()) { + rd->SetIsResizeSuppressed(); + // Since we are suppressing the resize reflow which would originally + // be triggered by view manager, we need to ensure that the refresh + // driver actually schedules a flush, otherwise it may get stuck. + rd->ScheduleViewManagerFlush(); + } + if (!aSize.IsEmpty()) { + if (nsViewManager* viewManager = aPresShell->GetViewManager()) { + if (aOldSize) { + viewManager->GetWindowDimensions(&aOldSize->width, &aOldSize->height); + } + viewManager->SetWindowDimensions(aSize.width, aSize.height); + } + } +} + +NS_IMETHODIMP +nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal) +{ + PROFILER_MARKER("Enter fullscreen"); + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_STATE(doc); + + // Notify the pres shell that we are starting fullscreen change, and + // set the window dimensions in advance. Since the resize message + // comes after the fullscreen change call, doing so could avoid an + // extra resize reflow after this point. + nsRect screenRect; + if (nsPresContext* presContext = GetPresContext()) { + presContext->DeviceContext()->GetRect(screenRect); + } + nsSize oldSize; + PrepareForFullscreenChange(GetPresShell(), screenRect.Size(), &oldSize); + OldWindowSize::Set(mWindow, oldSize); + + *aRetVal = nsIDocument::HandlePendingFullscreenRequests(doc); + return NS_OK; +} + +nsresult +nsDOMWindowUtils::ExitFullscreen() +{ + PROFILER_MARKER("Exit fullscreen"); + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_STATE(doc); + + // Although we would not use the old size if we have already exited + // fullscreen, we still want to cleanup in case we haven't. + nsSize oldSize = OldWindowSize::GetAndRemove(mWindow); + if (!doc->GetFullscreenElement()) { + return NS_OK; + } + + // Notify the pres shell that we are starting fullscreen change, and + // set the window dimensions in advance. Since the resize message + // comes after the fullscreen change call, doing so could avoid an + // extra resize reflow after this point. + PrepareForFullscreenChange(GetPresShell(), oldSize); + nsIDocument::ExitFullscreenInDocTree(doc); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SelectAtPoint(float aX, float aY, uint32_t aSelectBehavior, + bool *_retval) +{ + *_retval = false; + + nsSelectionAmount amount; + switch (aSelectBehavior) { + case nsIDOMWindowUtils::SELECT_CHARACTER: + amount = eSelectCharacter; + break; + case nsIDOMWindowUtils::SELECT_CLUSTER: + amount = eSelectCluster; + break; + case nsIDOMWindowUtils::SELECT_WORD: + amount = eSelectWord; + break; + case nsIDOMWindowUtils::SELECT_LINE: + amount = eSelectLine; + break; + case nsIDOMWindowUtils::SELECT_BEGINLINE: + amount = eSelectBeginLine; + break; + case nsIDOMWindowUtils::SELECT_ENDLINE: + amount = eSelectEndLine; + break; + case nsIDOMWindowUtils::SELECT_PARAGRAPH: + amount = eSelectParagraph; + break; + case nsIDOMWindowUtils::SELECT_WORDNOSPACE: + amount = eSelectWordNoSpace; + break; + default: + return NS_ERROR_INVALID_ARG; + } + + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_UNEXPECTED; + } + + // The root frame for this content window + nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame(); + if (!rootFrame) { + return NS_ERROR_UNEXPECTED; + } + + // Get the target frame at the client coordinates passed to us + nsPoint offset; + nsCOMPtr<nsIWidget> widget = GetWidget(&offset); + LayoutDeviceIntPoint pt = + nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext()); + nsPoint ptInRoot = + nsLayoutUtils::GetEventCoordinatesRelativeTo(widget, pt, rootFrame); + nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot); + // This can happen if the page hasn't loaded yet or if the point + // is outside the frame. + if (!targetFrame) { + return NS_ERROR_INVALID_ARG; + } + + // Convert point to coordinates relative to the target frame, which is + // what targetFrame's SelectByTypeAtPoint expects. + nsPoint relPoint = + nsLayoutUtils::GetEventCoordinatesRelativeTo(widget, pt, targetFrame); + + nsresult rv = + static_cast<nsFrame*>(targetFrame)-> + SelectByTypeAtPoint(GetPresContext(), relPoint, amount, amount, + nsFrame::SELECT_ACCUMULATE); + *_retval = !NS_FAILED(rv); + return NS_OK; +} + +static nsIDocument::additionalSheetType +convertSheetType(uint32_t aSheetType) +{ + switch(aSheetType) { + case nsDOMWindowUtils::AGENT_SHEET: + return nsIDocument::eAgentSheet; + case nsDOMWindowUtils::USER_SHEET: + return nsIDocument::eUserSheet; + case nsDOMWindowUtils::AUTHOR_SHEET: + return nsIDocument::eAuthorSheet; + default: + NS_ASSERTION(false, "wrong type"); + // we must return something although this should never happen + return nsIDocument::AdditionalSheetTypeCount; + } +} + +NS_IMETHODIMP +nsDOMWindowUtils::LoadSheet(nsIURI *aSheetURI, uint32_t aSheetType) +{ + NS_ENSURE_ARG_POINTER(aSheetURI); + NS_ENSURE_ARG(aSheetType == AGENT_SHEET || + aSheetType == USER_SHEET || + aSheetType == AUTHOR_SHEET); + + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); + + nsIDocument::additionalSheetType type = convertSheetType(aSheetType); + + return doc->LoadAdditionalStyleSheet(type, aSheetURI); +} + +NS_IMETHODIMP +nsDOMWindowUtils::LoadSheetUsingURIString(const nsACString& aSheetURI, uint32_t aSheetType) +{ + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI); + NS_ENSURE_SUCCESS(rv, rv); + + return LoadSheet(uri, aSheetType); +} + +NS_IMETHODIMP +nsDOMWindowUtils::AddSheet(nsIDOMStyleSheet *aSheet, uint32_t aSheetType) +{ + NS_ENSURE_ARG_POINTER(aSheet); + NS_ENSURE_ARG(aSheetType == AGENT_SHEET || + aSheetType == USER_SHEET || + aSheetType == AUTHOR_SHEET); + + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); + + nsIDocument::additionalSheetType type = convertSheetType(aSheetType); + RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet); + NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE); + if (sheet->GetOwningDocument()) { + return NS_ERROR_INVALID_ARG; + } + return doc->AddAdditionalStyleSheet(type, sheet); +} + +NS_IMETHODIMP +nsDOMWindowUtils::RemoveSheet(nsIURI *aSheetURI, uint32_t aSheetType) +{ + NS_ENSURE_ARG_POINTER(aSheetURI); + NS_ENSURE_ARG(aSheetType == AGENT_SHEET || + aSheetType == USER_SHEET || + aSheetType == AUTHOR_SHEET); + + nsCOMPtr<nsIDocument> doc = GetDocument(); + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); + + nsIDocument::additionalSheetType type = convertSheetType(aSheetType); + + doc->RemoveAdditionalStyleSheet(type, aSheetURI); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::RemoveSheetUsingURIString(const nsACString& aSheetURI, uint32_t aSheetType) +{ + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI); + NS_ENSURE_SUCCESS(rv, rv); + + return RemoveSheet(uri, aSheetType); +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetIsHandlingUserInput(bool* aHandlingUserInput) +{ + *aHandlingUserInput = EventStateManager::IsHandlingUserInput(); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetMillisSinceLastUserInput(double* aMillisSinceLastUserInput) +{ + TimeStamp lastInput = EventStateManager::LatestUserInputStart(); + if (lastInput.IsNull()) { + *aMillisSinceLastUserInput = 0; + return NS_OK; + } + + *aMillisSinceLastUserInput = (TimeStamp::Now() - lastInput).ToMilliseconds(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::AllowScriptsToClose() +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + nsGlobalWindow::Cast(window)->AllowScriptsToClose(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetIsParentWindowMainWidgetVisible(bool* aIsVisible) +{ + // this should reflect the "is parent window visible" logic in + // nsWindowWatcher::OpenWindowInternal() + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + nsCOMPtr<nsIWidget> parentWidget; + nsIDocShell *docShell = window->GetDocShell(); + if (docShell) { + if (TabChild *tabChild = TabChild::GetFrom(docShell)) { + if (!tabChild->SendIsParentWindowMainWidgetVisible(aIsVisible)) + return NS_ERROR_FAILURE; + return NS_OK; + } + + nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; + docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner)); + nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(parentTreeOwner)); + if (parentWindow) { + parentWindow->GetMainWidget(getter_AddRefs(parentWidget)); + } + } + if (!parentWidget) { + return NS_ERROR_NOT_AVAILABLE; + } + + *aIsVisible = parentWidget->IsVisible(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::IsNodeDisabledForEvents(nsIDOMNode* aNode, bool* aRetVal) +{ + *aRetVal = false; + nsCOMPtr<nsINode> n = do_QueryInterface(aNode); + nsINode* node = n; + while (node) { + if (node->IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) { + nsCOMPtr<nsIFormControl> fc = do_QueryInterface(node); + if (fc && fc->IsDisabledForEvents(eVoidEvent)) { + *aRetVal = true; + break; + } + } + node = node->GetParentNode(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetPaintFlashing(bool aPaintFlashing) +{ + nsPresContext* presContext = GetPresContext(); + if (presContext) { + presContext->SetPaintFlashing(aPaintFlashing); + // Clear paint flashing colors + nsIPresShell* presShell = GetPresShell(); + if (!aPaintFlashing && presShell) { + nsIFrame* rootFrame = presShell->GetRootFrame(); + if (rootFrame) { + rootFrame->InvalidateFrameSubtree(); + } + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetPaintFlashing(bool* aRetVal) +{ + *aRetVal = false; + nsPresContext* presContext = GetPresContext(); + if (presContext) { + *aRetVal = presContext->GetPaintFlashing(); + } + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::DispatchEventToChromeOnly(nsIDOMEventTarget* aTarget, + nsIDOMEvent* aEvent, + bool* aRetVal) +{ + *aRetVal = false; + NS_ENSURE_STATE(aTarget && aEvent); + aEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true; + aTarget->DispatchEvent(aEvent, aRetVal); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::RequestCompositorProperty(const nsAString& property, + float* aResult) +{ + if (nsIWidget* widget = GetWidget()) { + mozilla::layers::LayerManager* manager = widget->GetLayerManager(); + if (manager) { + *aResult = manager->RequestProperty(property); + return NS_OK; + } + } + + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetOMTAStyle(nsIDOMElement* aElement, + const nsAString& aProperty, + const nsAString& aPseudoElement, + nsAString& aResult) +{ + nsCOMPtr<Element> element = do_QueryInterface(aElement); + if (!element) { + return NS_ERROR_INVALID_ARG; + } + + RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr; + nsIFrame* frame = element->GetPrimaryFrame(); + if (frame && !aPseudoElement.IsEmpty()) { + if (aPseudoElement.EqualsLiteral("::before")) { + frame = nsLayoutUtils::GetBeforeFrame(frame); + } else if (aPseudoElement.EqualsLiteral("::after")) { + frame = nsLayoutUtils::GetAfterFrame(frame); + } else { + return NS_ERROR_INVALID_ARG; + } + } + if (frame && nsLayoutUtils::AreAsyncAnimationsEnabled()) { + if (aProperty.EqualsLiteral("opacity")) { + Layer* layer = + FrameLayerBuilder::GetDedicatedLayer(frame, + nsDisplayItem::TYPE_OPACITY); + if (layer) { + ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder(); + if (forwarder && forwarder->HasShadowManager()) { + float value; + bool hadAnimatedOpacity; + forwarder->GetShadowManager()->SendGetAnimationOpacity( + layer->AsShadowableLayer()->GetShadow(), + &value, &hadAnimatedOpacity); + + if (hadAnimatedOpacity) { + cssValue = new nsROCSSPrimitiveValue; + cssValue->SetNumber(value); + } + } + } + } else if (aProperty.EqualsLiteral("transform")) { + Layer* layer = + FrameLayerBuilder::GetDedicatedLayer(frame, + nsDisplayItem::TYPE_TRANSFORM); + if (layer) { + ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder(); + if (forwarder && forwarder->HasShadowManager()) { + MaybeTransform transform; + forwarder->GetShadowManager()->SendGetAnimationTransform( + layer->AsShadowableLayer()->GetShadow(), &transform); + if (transform.type() == MaybeTransform::TMatrix4x4) { + Matrix4x4 matrix = transform.get_Matrix4x4(); + cssValue = nsComputedDOMStyle::MatrixToCSSValue(matrix); + } + } + } + } + } + + if (cssValue) { + nsString text; + ErrorResult rv; + cssValue->GetCssText(text, rv); + aResult.Assign(text); + return rv.StealNSResult(); + } else { + aResult.Truncate(); + } + + return NS_OK; +} + +namespace { + +class HandlingUserInputHelper final : public nsIJSRAIIHelper +{ +public: + explicit HandlingUserInputHelper(bool aHandlingUserInput); + + NS_DECL_ISUPPORTS + NS_DECL_NSIJSRAIIHELPER + +private: + ~HandlingUserInputHelper(); + + bool mHandlingUserInput; + bool mDestructCalled; +}; + +NS_IMPL_ISUPPORTS(HandlingUserInputHelper, nsIJSRAIIHelper) + +HandlingUserInputHelper::HandlingUserInputHelper(bool aHandlingUserInput) + : mHandlingUserInput(aHandlingUserInput), + mDestructCalled(false) +{ + if (aHandlingUserInput) { + EventStateManager::StartHandlingUserInput(); + } +} + +HandlingUserInputHelper::~HandlingUserInputHelper() +{ + // We assert, but just in case, make sure we notify the ESM. + MOZ_ASSERT(mDestructCalled); + if (!mDestructCalled) { + Destruct(); + } +} + +NS_IMETHODIMP +HandlingUserInputHelper::Destruct() +{ + if (NS_WARN_IF(mDestructCalled)) { + return NS_ERROR_FAILURE; + } + + mDestructCalled = true; + if (mHandlingUserInput) { + EventStateManager::StopHandlingUserInput(); + } + + return NS_OK; +} + +} // unnamed namespace + +NS_IMETHODIMP +nsDOMWindowUtils::SetHandlingUserInput(bool aHandlingUserInput, + nsIJSRAIIHelper** aHelper) +{ + if (!nsContentUtils::IsCallerChrome()) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + RefPtr<HandlingUserInputHelper> helper( + new HandlingUserInputHelper(aHandlingUserInput)); + helper.forget(aHelper); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetContentAPZTestData(JSContext* aContext, + JS::MutableHandleValue aOutContentTestData) +{ + if (nsIWidget* widget = GetWidget()) { + RefPtr<LayerManager> lm = widget->GetLayerManager(); + if (!lm) { + return NS_OK; + } + if (ClientLayerManager* clm = lm->AsClientLayerManager()) { + if (!clm->GetAPZTestData().ToJS(aOutContentTestData, aContext)) { + return NS_ERROR_FAILURE; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetCompositorAPZTestData(JSContext* aContext, + JS::MutableHandleValue aOutCompositorTestData) +{ + if (nsIWidget* widget = GetWidget()) { + RefPtr<LayerManager> lm = widget->GetLayerManager(); + if (!lm) { + return NS_OK; + } + if (ClientLayerManager* clm = lm->AsClientLayerManager()) { + APZTestData compositorSideData; + clm->GetCompositorSideAPZTestData(&compositorSideData); + if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) { + return NS_ERROR_FAILURE; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::PostRestyleSelfEvent(nsIDOMElement* aElement) +{ + nsCOMPtr<Element> element = do_QueryInterface(aElement); + if (!element) { + return NS_ERROR_INVALID_ARG; + } + + nsLayoutUtils::PostRestyleEvent(element, eRestyle_Self, nsChangeHint(0)); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetMediaSuspend(uint32_t* aSuspend) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + *aSuspend = window->GetMediaSuspend(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetMediaSuspend(uint32_t aSuspend) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + window->SetMediaSuspend(aSuspend); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetAudioMuted(bool* aMuted) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + *aMuted = window->GetAudioMuted(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetAudioMuted(bool aMuted) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + window->SetAudioMuted(aMuted); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetAudioVolume(float* aVolume) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + *aVolume = window->GetAudioVolume(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetAudioVolume(float aVolume) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + return window->SetAudioVolume(aVolume); +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetChromeMargin(int32_t aTop, + int32_t aRight, + int32_t aBottom, + int32_t aLeft) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + if (window) { + nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(window->GetDocShell()); + if (baseWindow) { + nsCOMPtr<nsIWidget> widget; + baseWindow->GetMainWidget(getter_AddRefs(widget)); + if (widget) { + LayoutDeviceIntMargin margins(aTop, aRight, aBottom, aLeft); + return widget->SetNonClientMargins(margins); + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetFrameUniformityTestData(JSContext* aContext, + JS::MutableHandleValue aOutFrameUniformity) +{ + nsIWidget* widget = GetWidget(); + if (!widget) { + return NS_ERROR_NOT_AVAILABLE; + } + + RefPtr<LayerManager> manager = widget->GetLayerManager(); + if (!manager) { + return NS_ERROR_NOT_AVAILABLE; + } + + FrameUniformityData outData; + manager->GetFrameUniformity(&outData); + outData.ToJS(aOutFrameUniformity, aContext); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::XpconnectArgument(nsIDOMWindowUtils* aThis) +{ + // Do nothing. + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::AskPermission(nsIContentPermissionRequest* aRequest) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + return nsContentPermissionUtils::AskPermission(aRequest, window->GetCurrentInnerWindow()); +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetElementsRestyled(uint64_t* aResult) +{ + nsPresContext* presContext = GetPresContext(); + if (!presContext) { + return NS_ERROR_NOT_AVAILABLE; + } + + *aResult = presContext->ElementsRestyledCount(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetFramesConstructed(uint64_t* aResult) +{ + nsPresContext* presContext = GetPresContext(); + if (!presContext) { + return NS_ERROR_NOT_AVAILABLE; + } + + *aResult = presContext->FramesConstructedCount(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetFramesReflowed(uint64_t* aResult) +{ + nsPresContext* presContext = GetPresContext(); + if (!presContext) { + return NS_ERROR_NOT_AVAILABLE; + } + + *aResult = presContext->FramesReflowedCount(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetServiceWorkersTestingEnabled(bool aEnabled) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + window->SetServiceWorkersTestingEnabled(aEnabled); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetServiceWorkersTestingEnabled(bool *aEnabled) +{ + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + *aEnabled = window->GetServiceWorkersTestingEnabled(); + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::EnterChaosMode() +{ + ChaosMode::enterChaosMode(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::LeaveChaosMode() +{ + ChaosMode::leaveChaosMode(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::ForceUseCounterFlush(nsIDOMNode *aNode) +{ + NS_ENSURE_ARG_POINTER(aNode); + + if (nsCOMPtr<nsIDocument> doc = do_QueryInterface(aNode)) { + mozilla::css::ImageLoader* loader = doc->StyleImageLoader(); + loader->FlushUseCounters(); + + static_cast<nsDocument*>(doc.get())->ReportUseCounters(); + return NS_OK; + } + + if (nsCOMPtr<nsIContent> content = do_QueryInterface(aNode)) { + if (HTMLImageElement* img = HTMLImageElement::FromContent(content)) { + img->FlushUseCounters(); + return NS_OK; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType, + bool* aRetVal) +{ + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + + return presShell->HasRuleProcessorUsedByMultipleStyleSets(aSheetType, + aRetVal); +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetNextPaintSyncId(int32_t aSyncId) +{ + if (nsIWidget* widget = GetWidget()) { + RefPtr<LayerManager> lm = widget->GetLayerManager(); + if (lm && lm->AsClientLayerManager()) { + lm->AsClientLayerManager()->SetNextPaintSyncId(aSyncId); + return NS_OK; + } + } + + NS_WARNING("Paint sync id could not be set on the ClientLayerManager"); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::RespectDisplayPortSuppression(bool aEnabled) +{ + nsCOMPtr<nsIPresShell> shell(GetPresShell()); + APZCCallbackHelper::RespectDisplayPortSuppression(aEnabled, shell); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::ForceReflowInterrupt() +{ + nsPresContext* pc = GetPresContext(); + if (!pc) { + return NS_ERROR_NOT_AVAILABLE; + } + pc->SetPendingInterruptFromTest(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::TerminateGPUProcess() +{ + GPUProcessManager* pm = GPUProcessManager::Get(); + if (pm) { + pm->KillProcess(); + } + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::GetGpuProcessPid(int32_t* aPid) +{ + GPUProcessManager* pm = GPUProcessManager::Get(); + if (pm) { + *aPid = pm->GPUProcessPid(); + } else { + *aPid = -1; + } + + return NS_OK; +} + +NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsTranslationNodeList) +NS_IMPL_RELEASE(nsTranslationNodeList) + +NS_IMETHODIMP +nsTranslationNodeList::Item(uint32_t aIndex, nsIDOMNode** aRetVal) +{ + NS_ENSURE_ARG_POINTER(aRetVal); + NS_IF_ADDREF(*aRetVal = mNodes.SafeElementAt(aIndex)); + return NS_OK; +} + +NS_IMETHODIMP +nsTranslationNodeList::IsTranslationRootAtIndex(uint32_t aIndex, bool* aRetVal) +{ + NS_ENSURE_ARG_POINTER(aRetVal); + if (aIndex >= mLength) { + *aRetVal = false; + return NS_OK; + } + + *aRetVal = mNodeIsRoot.ElementAt(aIndex); + return NS_OK; +} + +NS_IMETHODIMP +nsTranslationNodeList::GetLength(uint32_t* aRetVal) +{ + NS_ENSURE_ARG_POINTER(aRetVal); + *aRetVal = mLength; + return NS_OK; +} |