Line data Source code
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 file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef mozilla_dom_ToJSValue_h
8 : #define mozilla_dom_ToJSValue_h
9 :
10 : #include "mozilla/TypeTraits.h"
11 : #include "mozilla/Assertions.h"
12 : #include "mozilla/dom/BindingUtils.h"
13 : #include "mozilla/dom/TypedArray.h"
14 : #include "jsapi.h"
15 : #include "nsISupports.h"
16 : #include "nsTArray.h"
17 : #include "nsWrapperCache.h"
18 :
19 : namespace mozilla {
20 : namespace dom {
21 :
22 : class Promise;
23 :
24 : // If ToJSValue returns false, it must set an exception on the
25 : // JSContext.
26 :
27 : // Accept strings.
28 : MOZ_MUST_USE bool
29 : ToJSValue(JSContext* aCx,
30 : const nsAString& aArgument,
31 : JS::MutableHandle<JS::Value> aValue);
32 :
33 : // Accept booleans. But be careful here: if we just have a function that takes
34 : // a boolean argument, then any pointer that doesn't match one of our other
35 : // signatures/templates will get treated as a boolean, which is clearly not
36 : // desirable. So make this a template that only gets used if the argument type
37 : // is actually boolean
38 : template<typename T>
39 : MOZ_MUST_USE
40 : typename EnableIf<IsSame<T, bool>::value, bool>::Type
41 0 : ToJSValue(JSContext* aCx,
42 : T aArgument,
43 : JS::MutableHandle<JS::Value> aValue)
44 : {
45 : // Make sure we're called in a compartment
46 0 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
47 :
48 0 : aValue.setBoolean(aArgument);
49 0 : return true;
50 : }
51 :
52 : // Accept integer types
53 : inline bool
54 0 : ToJSValue(JSContext* aCx,
55 : int32_t aArgument,
56 : JS::MutableHandle<JS::Value> aValue)
57 : {
58 : // Make sure we're called in a compartment
59 0 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
60 :
61 0 : aValue.setInt32(aArgument);
62 0 : return true;
63 : }
64 :
65 : inline bool
66 0 : ToJSValue(JSContext* aCx,
67 : uint32_t aArgument,
68 : JS::MutableHandle<JS::Value> aValue)
69 : {
70 : // Make sure we're called in a compartment
71 0 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
72 :
73 0 : aValue.setNumber(aArgument);
74 0 : return true;
75 : }
76 :
77 : inline bool
78 : ToJSValue(JSContext* aCx,
79 : int64_t aArgument,
80 : JS::MutableHandle<JS::Value> aValue)
81 : {
82 : // Make sure we're called in a compartment
83 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
84 :
85 : aValue.setNumber(double(aArgument));
86 : return true;
87 : }
88 :
89 : inline bool
90 : ToJSValue(JSContext* aCx,
91 : uint64_t aArgument,
92 : JS::MutableHandle<JS::Value> aValue)
93 : {
94 : // Make sure we're called in a compartment
95 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
96 :
97 : aValue.setNumber(double(aArgument));
98 : return true;
99 : }
100 :
101 : // accept floating point types
102 : inline bool
103 : ToJSValue(JSContext* aCx,
104 : float aArgument,
105 : JS::MutableHandle<JS::Value> aValue)
106 : {
107 : // Make sure we're called in a compartment
108 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
109 :
110 : aValue.setNumber(aArgument);
111 : return true;
112 : }
113 :
114 : inline bool
115 0 : ToJSValue(JSContext* aCx,
116 : double aArgument,
117 : JS::MutableHandle<JS::Value> aValue)
118 : {
119 : // Make sure we're called in a compartment
120 0 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
121 :
122 0 : aValue.setNumber(aArgument);
123 0 : return true;
124 : }
125 :
126 : // Accept CallbackObjects
127 : MOZ_MUST_USE inline bool
128 : ToJSValue(JSContext* aCx,
129 : CallbackObject& aArgument,
130 : JS::MutableHandle<JS::Value> aValue)
131 : {
132 : // Make sure we're called in a compartment
133 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
134 :
135 : aValue.setObjectOrNull(aArgument.CallbackOrNull());
136 :
137 : return MaybeWrapValue(aCx, aValue);
138 : }
139 :
140 : // Accept objects that inherit from nsWrapperCache (e.g. most
141 : // DOM objects).
142 : template <class T>
143 : MOZ_MUST_USE
144 : typename EnableIf<IsBaseOf<nsWrapperCache, T>::value, bool>::Type
145 33 : ToJSValue(JSContext* aCx,
146 : T& aArgument,
147 : JS::MutableHandle<JS::Value> aValue)
148 : {
149 : // Make sure we're called in a compartment
150 33 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
151 : // Make sure non-webidl objects don't sneak in here
152 33 : MOZ_ASSERT(aArgument.IsDOMBinding());
153 :
154 33 : return GetOrCreateDOMReflector(aCx, aArgument, aValue);
155 : }
156 :
157 : // Accept typed arrays built from appropriate nsTArray values
158 : template<typename T>
159 : MOZ_MUST_USE
160 : typename EnableIf<IsBaseOf<AllTypedArraysBase, T>::value, bool>::Type
161 0 : ToJSValue(JSContext* aCx,
162 : const TypedArrayCreator<T>& aArgument,
163 : JS::MutableHandle<JS::Value> aValue)
164 : {
165 : // Make sure we're called in a compartment
166 0 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
167 :
168 0 : JSObject* obj = aArgument.Create(aCx);
169 0 : if (!obj) {
170 0 : return false;
171 : }
172 0 : aValue.setObject(*obj);
173 0 : return true;
174 : }
175 :
176 : // Accept objects that inherit from nsISupports but not nsWrapperCache (e.g.
177 : // DOM File).
178 : template <class T>
179 : MOZ_MUST_USE
180 : typename EnableIf<!IsBaseOf<nsWrapperCache, T>::value &&
181 : !IsBaseOf<CallbackObject, T>::value &&
182 : IsBaseOf<nsISupports, T>::value, bool>::Type
183 22 : ToJSValue(JSContext* aCx,
184 : T& aArgument,
185 : JS::MutableHandle<JS::Value> aValue)
186 : {
187 : // Make sure we're called in a compartment
188 22 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
189 :
190 44 : qsObjectHelper helper(ToSupports(&aArgument), nullptr);
191 44 : JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
192 44 : return XPCOMObjectToJsval(aCx, scope, helper, nullptr, true, aValue);
193 : }
194 :
195 : // Accept nsRefPtr/nsCOMPtr
196 : template <typename T>
197 : MOZ_MUST_USE bool
198 7 : ToJSValue(JSContext* aCx,
199 : const nsCOMPtr<T>& aArgument,
200 : JS::MutableHandle<JS::Value> aValue)
201 : {
202 7 : return ToJSValue(aCx, *aArgument.get(), aValue);
203 : }
204 :
205 : template <typename T>
206 : MOZ_MUST_USE bool
207 2 : ToJSValue(JSContext* aCx,
208 : const RefPtr<T>& aArgument,
209 : JS::MutableHandle<JS::Value> aValue)
210 : {
211 2 : return ToJSValue(aCx, *aArgument.get(), aValue);
212 : }
213 :
214 : template <typename T>
215 : MOZ_MUST_USE bool
216 0 : ToJSValue(JSContext* aCx,
217 : const NonNull<T>& aArgument,
218 : JS::MutableHandle<JS::Value> aValue)
219 : {
220 0 : return ToJSValue(aCx, *aArgument.get(), aValue);
221 : }
222 :
223 : // Accept WebIDL dictionaries
224 : template <class T>
225 : MOZ_MUST_USE
226 : typename EnableIf<IsBaseOf<DictionaryBase, T>::value, bool>::Type
227 5 : ToJSValue(JSContext* aCx,
228 : const T& aArgument,
229 : JS::MutableHandle<JS::Value> aValue)
230 : {
231 5 : return aArgument.ToObjectInternal(aCx, aValue);
232 : }
233 :
234 : // Accept existing JS values (which may not be same-compartment with us
235 : MOZ_MUST_USE inline bool
236 0 : ToJSValue(JSContext* aCx, JS::Handle<JS::Value> aArgument,
237 : JS::MutableHandle<JS::Value> aValue)
238 : {
239 0 : aValue.set(aArgument);
240 0 : return MaybeWrapValue(aCx, aValue);
241 : }
242 :
243 : // Accept existing JS values on the Heap (which may not be same-compartment with us
244 : MOZ_MUST_USE inline bool
245 0 : ToJSValue(JSContext* aCx, const JS::Heap<JS::Value>& aArgument,
246 : JS::MutableHandle<JS::Value> aValue)
247 : {
248 0 : aValue.set(aArgument);
249 0 : return MaybeWrapValue(aCx, aValue);
250 : }
251 :
252 : // Accept existing rooted JS values (which may not be same-compartment with us
253 : MOZ_MUST_USE inline bool
254 0 : ToJSValue(JSContext* aCx, const JS::Rooted<JS::Value>& aArgument,
255 : JS::MutableHandle<JS::Value> aValue)
256 : {
257 0 : aValue.set(aArgument);
258 0 : return MaybeWrapValue(aCx, aValue);
259 : }
260 :
261 : // Accept existing rooted JS objects (which may not be same-compartment with
262 : // us).
263 : MOZ_MUST_USE inline bool
264 0 : ToJSValue(JSContext* aCx, const JS::Rooted<JSObject*>& aArgument,
265 : JS::MutableHandle<JS::Value> aValue)
266 : {
267 0 : aValue.setObjectOrNull(aArgument);
268 0 : return MaybeWrapObjectOrNullValue(aCx, aValue);
269 : }
270 :
271 : // Accept nsresult, for use in rejections, and create an XPCOM
272 : // exception object representing that nsresult.
273 : MOZ_MUST_USE bool
274 : ToJSValue(JSContext* aCx,
275 : nsresult aArgument,
276 : JS::MutableHandle<JS::Value> aValue);
277 :
278 : // Accept ErrorResult, for use in rejections, and create an exception
279 : // representing the failure. Note, the ErrorResult must indicate a failure
280 : // with aArgument.Failure() returning true.
281 : MOZ_MUST_USE bool
282 : ToJSValue(JSContext* aCx,
283 : ErrorResult& aArgument,
284 : JS::MutableHandle<JS::Value> aValue);
285 :
286 : // Accept owning WebIDL unions.
287 : template <typename T>
288 : MOZ_MUST_USE
289 : typename EnableIf<IsBaseOf<AllOwningUnionBase, T>::value, bool>::Type
290 0 : ToJSValue(JSContext* aCx,
291 : const T& aArgument,
292 : JS::MutableHandle<JS::Value> aValue)
293 : {
294 0 : JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
295 0 : return aArgument.ToJSVal(aCx, global, aValue);
296 : }
297 :
298 : // Accept pointers to other things we accept
299 : template <typename T>
300 : MOZ_MUST_USE
301 : typename EnableIf<IsPointer<T>::value, bool>::Type
302 47 : ToJSValue(JSContext* aCx,
303 : T aArgument,
304 : JS::MutableHandle<JS::Value> aValue)
305 : {
306 47 : return ToJSValue(aCx, *aArgument, aValue);
307 : }
308 :
309 : // Accept Promise objects, which need special handling.
310 : MOZ_MUST_USE bool
311 : ToJSValue(JSContext* aCx,
312 : Promise& aArgument,
313 : JS::MutableHandle<JS::Value> aValue);
314 :
315 : // Accept arrays of other things we accept
316 : template <typename T>
317 : MOZ_MUST_USE bool
318 46 : ToJSValue(JSContext* aCx,
319 : T* aArguments,
320 : size_t aLength,
321 : JS::MutableHandle<JS::Value> aValue)
322 : {
323 : // Make sure we're called in a compartment
324 46 : MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
325 :
326 92 : JS::AutoValueVector v(aCx);
327 46 : if (!v.resize(aLength)) {
328 0 : return false;
329 : }
330 46 : for (size_t i = 0; i < aLength; ++i) {
331 0 : if (!ToJSValue(aCx, aArguments[i], v[i])) {
332 0 : return false;
333 : }
334 : }
335 46 : JSObject* arrayObj = JS_NewArrayObject(aCx, v);
336 46 : if (!arrayObj) {
337 0 : return false;
338 : }
339 46 : aValue.setObject(*arrayObj);
340 46 : return true;
341 : }
342 :
343 : template <typename T>
344 : MOZ_MUST_USE bool
345 46 : ToJSValue(JSContext* aCx,
346 : const nsTArray<T>& aArgument,
347 : JS::MutableHandle<JS::Value> aValue)
348 : {
349 46 : return ToJSValue(aCx, aArgument.Elements(),
350 46 : aArgument.Length(), aValue);
351 : }
352 :
353 : template <typename T>
354 : MOZ_MUST_USE bool
355 0 : ToJSValue(JSContext* aCx,
356 : const FallibleTArray<T>& aArgument,
357 : JS::MutableHandle<JS::Value> aValue)
358 : {
359 0 : return ToJSValue(aCx, aArgument.Elements(),
360 0 : aArgument.Length(), aValue);
361 : }
362 :
363 : template <typename T, int N>
364 : MOZ_MUST_USE bool
365 0 : ToJSValue(JSContext* aCx,
366 : const T(&aArgument)[N],
367 : JS::MutableHandle<JS::Value> aValue)
368 : {
369 0 : return ToJSValue(aCx, aArgument, N, aValue);
370 : }
371 :
372 : } // namespace dom
373 : } // namespace mozilla
374 :
375 : #endif /* mozilla_dom_ToJSValue_h */
|