Bug 1698238 return default dictionary from GetUserMediaRequest#getConstraints() if...
[gecko.git] / dom / base / nsJSUtils.h
blobc47a5a8c78bd28e4a5afa048cd56ad762a7a684f
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef nsJSUtils_h__
8 #define nsJSUtils_h__
10 /**
11 * This is not a generated file. It contains common utility functions
12 * invoked from the JavaScript code generated from IDL interfaces.
13 * The goal of the utility functions is to cut down on the size of
14 * the generated code itself.
17 #include "mozilla/Assertions.h"
19 #include "jsapi.h"
20 #include "js/Conversions.h"
21 #include "js/String.h" // JS::{,Lossy}CopyLinearStringChars, JS::CopyStringChars, JS::Get{,Linear}StringLength, JS::MaxStringLength, JS::StringHasLatin1Chars
22 #include "nsString.h"
23 #include "xpcpublic.h"
25 class nsIScriptContext;
26 class nsIScriptElement;
27 class nsIScriptGlobalObject;
28 class nsXBLPrototypeBinding;
30 namespace mozilla {
31 union Utf8Unit;
33 namespace dom {
34 class AutoJSAPI;
35 class Element;
36 } // namespace dom
37 } // namespace mozilla
39 class nsJSUtils {
40 public:
41 static bool GetCallingLocation(JSContext* aContext, nsACString& aFilename,
42 uint32_t* aLineno = nullptr,
43 uint32_t* aColumn = nullptr);
44 static bool GetCallingLocation(JSContext* aContext, nsAString& aFilename,
45 uint32_t* aLineno = nullptr,
46 uint32_t* aColumn = nullptr);
48 /**
49 * Retrieve the inner window ID based on the given JSContext.
51 * @param JSContext aContext
52 * The JSContext from which you want to find the inner window ID.
54 * @returns uint64_t the inner window ID.
56 static uint64_t GetCurrentlyRunningCodeInnerWindowID(JSContext* aContext);
58 static nsresult CompileFunction(mozilla::dom::AutoJSAPI& jsapi,
59 JS::HandleVector<JSObject*> aScopeChain,
60 JS::CompileOptions& aOptions,
61 const nsACString& aName, uint32_t aArgCount,
62 const char** aArgArray,
63 const nsAString& aBody,
64 JSObject** aFunctionObject);
66 static nsresult CompileModule(JSContext* aCx,
67 JS::SourceText<char16_t>& aSrcBuf,
68 JS::Handle<JSObject*> aEvaluationGlobal,
69 JS::CompileOptions& aCompileOptions,
70 JS::MutableHandle<JSObject*> aModule);
72 static nsresult CompileModule(JSContext* aCx,
73 JS::SourceText<mozilla::Utf8Unit>& aSrcBuf,
74 JS::Handle<JSObject*> aEvaluationGlobal,
75 JS::CompileOptions& aCompileOptions,
76 JS::MutableHandle<JSObject*> aModule);
78 static nsresult ModuleInstantiate(JSContext* aCx,
79 JS::Handle<JSObject*> aModule);
82 * Wrapper for JSAPI ModuleEvaluate function.
84 * @param JSContext aCx
85 * The JSContext where this is executed.
86 * @param JS::Handle<JSObject*> aModule
87 * The module to be evaluated.
88 * @param JS::Handle<Value*> aResult
89 * If Top level await is enabled:
90 * The evaluation promise returned from evaluating the module.
91 * Otherwise:
92 * Undefined
94 static nsresult ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule,
95 JS::MutableHandle<JS::Value> aResult);
97 // Returns false if an exception got thrown on aCx. Passing a null
98 // aElement is allowed; that wil produce an empty aScopeChain.
99 static bool GetScopeChainForElement(
100 JSContext* aCx, mozilla::dom::Element* aElement,
101 JS::MutableHandleVector<JSObject*> aScopeChain);
103 static void ResetTimeZone();
105 static bool DumpEnabled();
108 inline void AssignFromStringBuffer(nsStringBuffer* buffer, size_t len,
109 nsAString& dest) {
110 buffer->ToString(len, dest);
113 template <typename T, typename std::enable_if_t<std::is_same<
114 typename T::char_type, char16_t>::value>* = nullptr>
115 inline bool AssignJSString(JSContext* cx, T& dest, JSString* s) {
116 size_t len = JS::GetStringLength(s);
117 static_assert(JS::MaxStringLength < (1 << 30),
118 "Shouldn't overflow here or in SetCapacity");
120 const char16_t* chars;
121 if (XPCStringConvert::MaybeGetDOMStringChars(s, &chars)) {
122 // The characters represent an existing string buffer that we shared with
123 // JS. We can share that buffer ourselves if the string corresponds to the
124 // whole buffer; otherwise we have to copy.
125 if (chars[len] == '\0') {
126 AssignFromStringBuffer(
127 nsStringBuffer::FromData(const_cast<char16_t*>(chars)), len, dest);
128 return true;
130 } else if (XPCStringConvert::MaybeGetLiteralStringChars(s, &chars)) {
131 // The characters represent a literal char16_t string constant
132 // compiled into libxul; we can just use it as-is.
133 dest.AssignLiteral(chars, len);
134 return true;
137 // We don't bother checking for a dynamic-atom external string, because we'd
138 // just need to copy out of it anyway.
140 if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
141 JS_ReportOutOfMemory(cx);
142 return false;
144 return JS::CopyStringChars(cx, dest.BeginWriting(), s, len);
147 // Specialization for UTF8String.
148 template <typename T, typename std::enable_if_t<std::is_same<
149 typename T::char_type, char>::value>* = nullptr>
150 inline bool AssignJSString(JSContext* cx, T& dest, JSString* s) {
151 using namespace mozilla;
152 CheckedInt<size_t> bufLen(JS::GetStringLength(s));
153 // From the contract for JS_EncodeStringToUTF8BufferPartial, to guarantee that
154 // the whole string is converted.
155 if (JS::StringHasLatin1Chars(s)) {
156 bufLen *= 2;
157 } else {
158 bufLen *= 3;
161 if (MOZ_UNLIKELY(!bufLen.isValid())) {
162 JS_ReportOutOfMemory(cx);
163 return false;
166 // Shouldn't really matter, but worth being safe.
167 const bool kAllowShrinking = true;
169 auto handleOrErr = dest.BulkWrite(bufLen.value(), 0, kAllowShrinking);
170 if (MOZ_UNLIKELY(handleOrErr.isErr())) {
171 JS_ReportOutOfMemory(cx);
172 return false;
175 auto handle = handleOrErr.unwrap();
177 auto maybe = JS_EncodeStringToUTF8BufferPartial(cx, s, handle.AsSpan());
178 if (MOZ_UNLIKELY(!maybe)) {
179 JS_ReportOutOfMemory(cx);
180 return false;
183 size_t read;
184 size_t written;
185 Tie(read, written) = *maybe;
187 MOZ_ASSERT(read == JS::GetStringLength(s));
188 handle.Finish(written, kAllowShrinking);
189 return true;
192 inline void AssignJSLinearString(nsAString& dest, JSLinearString* s) {
193 size_t len = JS::GetLinearStringLength(s);
194 static_assert(JS::MaxStringLength < (1 << 30),
195 "Shouldn't overflow here or in SetCapacity");
196 dest.SetLength(len);
197 JS::CopyLinearStringChars(dest.BeginWriting(), s, len);
200 inline void AssignJSLinearString(nsACString& dest, JSLinearString* s) {
201 size_t len = JS::GetLinearStringLength(s);
202 static_assert(JS::MaxStringLength < (1 << 30),
203 "Shouldn't overflow here or in SetCapacity");
204 dest.SetLength(len);
205 JS::LossyCopyLinearStringChars(dest.BeginWriting(), s, len);
208 template <typename T>
209 class nsTAutoJSLinearString : public nsTAutoString<T> {
210 public:
211 explicit nsTAutoJSLinearString(JSLinearString* str) {
212 AssignJSLinearString(*this, str);
216 using nsAutoJSLinearString = nsTAutoJSLinearString<char16_t>;
217 using nsAutoJSLinearCString = nsTAutoJSLinearString<char>;
219 template <typename T>
220 class nsTAutoJSString : public nsTAutoString<T> {
221 public:
223 * nsTAutoJSString should be default constructed, which leaves it empty
224 * (this->IsEmpty()), and initialized with one of the init() methods below.
226 nsTAutoJSString() = default;
228 bool init(JSContext* aContext, JSString* str) {
229 return AssignJSString(aContext, *this, str);
232 bool init(JSContext* aContext, const JS::Value& v) {
233 if (v.isString()) {
234 return init(aContext, v.toString());
237 // Stringify, making sure not to run script.
238 JS::Rooted<JSString*> str(aContext);
239 if (v.isObject()) {
240 str = JS_NewStringCopyZ(aContext, "[Object]");
241 } else {
242 JS::Rooted<JS::Value> rootedVal(aContext, v);
243 str = JS::ToString(aContext, rootedVal);
246 return str && init(aContext, str);
249 bool init(JSContext* aContext, jsid id) {
250 JS::Rooted<JS::Value> v(aContext);
251 return JS_IdToValue(aContext, id, &v) && init(aContext, v);
254 bool init(const JS::Value& v);
256 ~nsTAutoJSString() = default;
259 using nsAutoJSString = nsTAutoJSString<char16_t>;
261 // Note that this is guaranteed to be UTF-8.
262 using nsAutoJSCString = nsTAutoJSString<char>;
264 #endif /* nsJSUtils_h__ */