Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / base / nsJSUtils.h
blob36e906061588aab50dee129cc46dd2e4d3e153f8
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/CompileOptions.h"
21 #include "js/Conversions.h"
22 #include "js/SourceText.h"
23 #include "js/String.h" // JS::{,Lossy}CopyLinearStringChars, JS::CopyStringChars, JS::Get{,Linear}StringLength, JS::MaxStringLength, JS::StringHasLatin1Chars
24 #include "js/Utility.h" // JS::FreePolicy
25 #include "nsString.h"
26 #include "xpcpublic.h"
28 class nsIScriptContext;
29 class nsIScriptElement;
30 class nsIScriptGlobalObject;
31 class nsXBLPrototypeBinding;
33 namespace mozilla {
34 union Utf8Unit;
36 namespace dom {
37 class AutoJSAPI;
38 class Element;
39 } // namespace dom
40 } // namespace mozilla
42 class nsJSUtils {
43 public:
44 static bool GetCallingLocation(JSContext* aContext, nsACString& aFilename,
45 uint32_t* aLineno = nullptr,
46 uint32_t* aColumn = nullptr);
47 static bool GetCallingLocation(JSContext* aContext, nsAString& aFilename,
48 uint32_t* aLineno = nullptr,
49 uint32_t* aColumn = nullptr);
51 /**
52 * Retrieve the inner window ID based on the given JSContext.
54 * @param JSContext aContext
55 * The JSContext from which you want to find the inner window ID.
57 * @returns uint64_t the inner window ID.
59 static uint64_t GetCurrentlyRunningCodeInnerWindowID(JSContext* aContext);
61 static nsresult CompileFunction(mozilla::dom::AutoJSAPI& jsapi,
62 JS::HandleVector<JSObject*> aScopeChain,
63 JS::CompileOptions& aOptions,
64 const nsACString& aName, uint32_t aArgCount,
65 const char** aArgArray,
66 const nsAString& aBody,
67 JSObject** aFunctionObject);
69 static nsresult UpdateFunctionDebugMetadata(
70 mozilla::dom::AutoJSAPI& jsapi, JS::Handle<JSObject*> aFun,
71 JS::CompileOptions& aOptions, JS::Handle<JSString*> aElementAttributeName,
72 JS::Handle<JS::Value> aPrivateValue);
74 static bool IsScriptable(JS::Handle<JSObject*> aEvaluationGlobal);
76 // Returns false if an exception got thrown on aCx. Passing a null
77 // aElement is allowed; that wil produce an empty aScopeChain.
78 static bool GetScopeChainForElement(
79 JSContext* aCx, mozilla::dom::Element* aElement,
80 JS::MutableHandleVector<JSObject*> aScopeChain);
82 static void ResetTimeZone();
84 static bool DumpEnabled();
86 // A helper function that receives buffer pointer, creates ArrayBuffer, and
87 // convert it to Uint8Array.
88 // Note that the buffer needs to be created by JS_malloc (or at least can be
89 // freed by JS_free), as the resulting Uint8Array takes the ownership of the
90 // buffer.
91 static JSObject* MoveBufferAsUint8Array(
92 JSContext* aCx, size_t aSize,
93 mozilla::UniquePtr<uint8_t[], JS::FreePolicy> aBuffer);
96 inline void AssignFromStringBuffer(nsStringBuffer* buffer, size_t len,
97 nsAString& dest) {
98 buffer->ToString(len, dest);
101 template <typename T, typename std::enable_if_t<std::is_same<
102 typename T::char_type, char16_t>::value>* = nullptr>
103 inline bool AssignJSString(JSContext* cx, T& dest, JSString* s) {
104 size_t len = JS::GetStringLength(s);
105 static_assert(JS::MaxStringLength < (1 << 30),
106 "Shouldn't overflow here or in SetCapacity");
108 const char16_t* chars;
109 if (XPCStringConvert::MaybeGetDOMStringChars(s, &chars)) {
110 // The characters represent an existing string buffer that we shared with
111 // JS. We can share that buffer ourselves if the string corresponds to the
112 // whole buffer; otherwise we have to copy.
113 if (chars[len] == '\0') {
114 AssignFromStringBuffer(
115 nsStringBuffer::FromData(const_cast<char16_t*>(chars)), len, dest);
116 return true;
118 } else if (XPCStringConvert::MaybeGetLiteralStringChars(s, &chars)) {
119 // The characters represent a literal char16_t string constant
120 // compiled into libxul; we can just use it as-is.
121 dest.AssignLiteral(chars, len);
122 return true;
125 // We don't bother checking for a dynamic-atom external string, because we'd
126 // just need to copy out of it anyway.
128 if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
129 JS_ReportOutOfMemory(cx);
130 return false;
132 return JS::CopyStringChars(cx, dest.BeginWriting(), s, len);
135 // Specialization for UTF8String.
136 template <typename T, typename std::enable_if_t<std::is_same<
137 typename T::char_type, char>::value>* = nullptr>
138 inline bool AssignJSString(JSContext* cx, T& dest, JSString* s) {
139 using namespace mozilla;
140 CheckedInt<size_t> bufLen(JS::GetStringLength(s));
141 // From the contract for JS_EncodeStringToUTF8BufferPartial, to guarantee that
142 // the whole string is converted.
143 if (JS::StringHasLatin1Chars(s)) {
144 bufLen *= 2;
145 } else {
146 bufLen *= 3;
149 if (MOZ_UNLIKELY(!bufLen.isValid())) {
150 JS_ReportOutOfMemory(cx);
151 return false;
154 // Shouldn't really matter, but worth being safe.
155 const bool kAllowShrinking = true;
157 auto handleOrErr = dest.BulkWrite(bufLen.value(), 0, kAllowShrinking);
158 if (MOZ_UNLIKELY(handleOrErr.isErr())) {
159 JS_ReportOutOfMemory(cx);
160 return false;
163 auto handle = handleOrErr.unwrap();
165 auto maybe = JS_EncodeStringToUTF8BufferPartial(cx, s, handle.AsSpan());
166 if (MOZ_UNLIKELY(!maybe)) {
167 JS_ReportOutOfMemory(cx);
168 return false;
171 size_t read;
172 size_t written;
173 std::tie(read, written) = *maybe;
175 MOZ_ASSERT(read == JS::GetStringLength(s));
176 handle.Finish(written, kAllowShrinking);
177 return true;
180 inline void AssignJSLinearString(nsAString& dest, JSLinearString* s) {
181 size_t len = JS::GetLinearStringLength(s);
182 static_assert(JS::MaxStringLength < (1 << 30),
183 "Shouldn't overflow here or in SetCapacity");
184 dest.SetLength(len);
185 JS::CopyLinearStringChars(dest.BeginWriting(), s, len);
188 inline void AssignJSLinearString(nsACString& dest, JSLinearString* s) {
189 size_t len = JS::GetLinearStringLength(s);
190 static_assert(JS::MaxStringLength < (1 << 30),
191 "Shouldn't overflow here or in SetCapacity");
192 dest.SetLength(len);
193 JS::LossyCopyLinearStringChars(dest.BeginWriting(), s, len);
196 template <typename T>
197 class nsTAutoJSLinearString : public nsTAutoString<T> {
198 public:
199 explicit nsTAutoJSLinearString(JSLinearString* str) {
200 AssignJSLinearString(*this, str);
204 using nsAutoJSLinearString = nsTAutoJSLinearString<char16_t>;
205 using nsAutoJSLinearCString = nsTAutoJSLinearString<char>;
207 template <typename T>
208 class nsTAutoJSString : public nsTAutoString<T> {
209 public:
211 * nsTAutoJSString should be default constructed, which leaves it empty
212 * (this->IsEmpty()), and initialized with one of the init() methods below.
214 nsTAutoJSString() = default;
216 bool init(JSContext* aContext, JSString* str) {
217 return AssignJSString(aContext, *this, str);
220 bool init(JSContext* aContext, const JS::Value& v) {
221 if (v.isString()) {
222 return init(aContext, v.toString());
225 // Stringify, making sure not to run script.
226 JS::Rooted<JSString*> str(aContext);
227 if (v.isObject()) {
228 str = JS_NewStringCopyZ(aContext, "[Object]");
229 } else {
230 JS::Rooted<JS::Value> rootedVal(aContext, v);
231 str = JS::ToString(aContext, rootedVal);
234 return str && init(aContext, str);
237 bool init(JSContext* aContext, jsid id) {
238 JS::Rooted<JS::Value> v(aContext);
239 return JS_IdToValue(aContext, id, &v) && init(aContext, v);
242 bool init(const JS::Value& v);
244 ~nsTAutoJSString() = default;
247 using nsAutoJSString = nsTAutoJSString<char16_t>;
249 // Note that this is guaranteed to be UTF-8.
250 using nsAutoJSCString = nsTAutoJSString<char>;
252 #endif /* nsJSUtils_h__ */