|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ |
|
2 /* vim: set ts=2 sw=2 et tw=79: */ |
|
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 // If ToJSValue returns false, it must set an exception on the |
|
23 // JSContext. |
|
24 |
|
25 // Accept strings. |
|
26 bool |
|
27 ToJSValue(JSContext* aCx, |
|
28 const nsAString& aArgument, |
|
29 JS::MutableHandle<JS::Value> aValue); |
|
30 |
|
31 // Accept booleans. |
|
32 inline bool |
|
33 ToJSValue(JSContext* aCx, |
|
34 bool aArgument, |
|
35 JS::MutableHandle<JS::Value> aValue) |
|
36 { |
|
37 // Make sure we're called in a compartment |
|
38 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
39 |
|
40 aValue.setBoolean(aArgument); |
|
41 return true; |
|
42 } |
|
43 |
|
44 // Accept integer types |
|
45 inline bool |
|
46 ToJSValue(JSContext* aCx, |
|
47 int32_t aArgument, |
|
48 JS::MutableHandle<JS::Value> aValue) |
|
49 { |
|
50 // Make sure we're called in a compartment |
|
51 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
52 |
|
53 aValue.setInt32(aArgument); |
|
54 return true; |
|
55 } |
|
56 |
|
57 // The uint32_t version is disabled for now because on the super-old b2g |
|
58 // compiler nsresult and uint32_t are the same type. If someone needs this at |
|
59 // some point we'll need to figure out how to make it work (e.g. by switching to |
|
60 // traits structs and using the trick IPC's ParamTraits uses, where a traits |
|
61 // struct templated on the type inherits from a base traits struct of some sort, |
|
62 // templated on the same type, or something). Maybe b2g will update to a modern |
|
63 // compiler before that happens.... |
|
64 #if 0 |
|
65 inline bool |
|
66 ToJSValue(JSContext* aCx, |
|
67 uint32_t aArgument, |
|
68 JS::MutableHandle<JS::Value> aValue) |
|
69 { |
|
70 // Make sure we're called in a compartment |
|
71 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
72 |
|
73 aValue.setNumber(aArgument); |
|
74 return true; |
|
75 } |
|
76 #endif |
|
77 |
|
78 inline bool |
|
79 ToJSValue(JSContext* aCx, |
|
80 int64_t aArgument, |
|
81 JS::MutableHandle<JS::Value> aValue) |
|
82 { |
|
83 // Make sure we're called in a compartment |
|
84 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
85 |
|
86 aValue.setNumber(double(aArgument)); |
|
87 return true; |
|
88 } |
|
89 |
|
90 inline bool |
|
91 ToJSValue(JSContext* aCx, |
|
92 uint64_t aArgument, |
|
93 JS::MutableHandle<JS::Value> aValue) |
|
94 { |
|
95 // Make sure we're called in a compartment |
|
96 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
97 |
|
98 aValue.setNumber(double(aArgument)); |
|
99 return true; |
|
100 } |
|
101 |
|
102 // accept floating point types |
|
103 inline bool |
|
104 ToJSValue(JSContext* aCx, |
|
105 float aArgument, |
|
106 JS::MutableHandle<JS::Value> aValue) |
|
107 { |
|
108 // Make sure we're called in a compartment |
|
109 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
110 |
|
111 aValue.setNumber(aArgument); |
|
112 return true; |
|
113 } |
|
114 |
|
115 inline bool |
|
116 ToJSValue(JSContext* aCx, |
|
117 double aArgument, |
|
118 JS::MutableHandle<JS::Value> aValue) |
|
119 { |
|
120 // Make sure we're called in a compartment |
|
121 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
122 |
|
123 aValue.setNumber(aArgument); |
|
124 return true; |
|
125 } |
|
126 |
|
127 // Accept objects that inherit from nsWrapperCache and nsISupports (e.g. most |
|
128 // DOM objects). |
|
129 template <class T> |
|
130 typename EnableIf<IsBaseOf<nsWrapperCache, T>::value && |
|
131 IsBaseOf<nsISupports, T>::value, bool>::Type |
|
132 ToJSValue(JSContext* aCx, |
|
133 T& aArgument, |
|
134 JS::MutableHandle<JS::Value> aValue) |
|
135 { |
|
136 // Make sure we're called in a compartment |
|
137 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
138 // Make sure non-webidl objects don't sneak in here |
|
139 MOZ_ASSERT(aArgument.IsDOMBinding()); |
|
140 |
|
141 return WrapNewBindingObject(aCx, aArgument, aValue); |
|
142 } |
|
143 |
|
144 // Accept typed arrays built from appropriate nsTArray values |
|
145 template<typename T> |
|
146 typename EnableIf<IsBaseOf<AllTypedArraysBase, T>::value, bool>::Type |
|
147 ToJSValue(JSContext* aCx, |
|
148 const TypedArrayCreator<T>& aArgument, |
|
149 JS::MutableHandle<JS::Value> aValue) |
|
150 { |
|
151 // Make sure we're called in a compartment |
|
152 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
153 |
|
154 JSObject* obj = aArgument.Create(aCx); |
|
155 if (!obj) { |
|
156 return false; |
|
157 } |
|
158 aValue.setObject(*obj); |
|
159 return true; |
|
160 } |
|
161 |
|
162 // We don't want to include nsContentUtils here, so use a helper |
|
163 // function for the nsISupports case. |
|
164 namespace tojsvalue_detail { |
|
165 bool |
|
166 ISupportsToJSValue(JSContext* aCx, |
|
167 nsISupports* aArgument, |
|
168 JS::MutableHandle<JS::Value> aValue); |
|
169 } // namespace tojsvalue_detail |
|
170 |
|
171 // Accept objects that inherit from nsISupports but not nsWrapperCache (e.g. |
|
172 // nsIDOMFile). |
|
173 template <class T> |
|
174 typename EnableIf<!IsBaseOf<nsWrapperCache, T>::value && |
|
175 IsBaseOf<nsISupports, T>::value, bool>::Type |
|
176 ToJSValue(JSContext* aCx, |
|
177 T& aArgument, |
|
178 JS::MutableHandle<JS::Value> aValue) |
|
179 { |
|
180 // Make sure we're called in a compartment |
|
181 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
182 |
|
183 return tojsvalue_detail::ISupportsToJSValue(aCx, &aArgument, aValue); |
|
184 } |
|
185 |
|
186 // Accept nsRefPtr/nsCOMPtr |
|
187 template <typename T> |
|
188 bool |
|
189 ToJSValue(JSContext* aCx, |
|
190 const nsCOMPtr<T>& aArgument, |
|
191 JS::MutableHandle<JS::Value> aValue) |
|
192 { |
|
193 return ToJSValue(aCx, *aArgument.get(), aValue); |
|
194 } |
|
195 |
|
196 template <typename T> |
|
197 bool |
|
198 ToJSValue(JSContext* aCx, |
|
199 const nsRefPtr<T>& aArgument, |
|
200 JS::MutableHandle<JS::Value> aValue) |
|
201 { |
|
202 return ToJSValue(aCx, *aArgument.get(), aValue); |
|
203 } |
|
204 |
|
205 // Accept WebIDL dictionaries |
|
206 template <class T> |
|
207 typename EnableIf<IsBaseOf<DictionaryBase, T>::value, bool>::Type |
|
208 ToJSValue(JSContext* aCx, |
|
209 const T& aArgument, |
|
210 JS::MutableHandle<JS::Value> aValue) |
|
211 { |
|
212 return aArgument.ToObject(aCx, aValue); |
|
213 } |
|
214 |
|
215 // Accept existing JS values (which may not be same-compartment with us |
|
216 inline bool |
|
217 ToJSValue(JSContext* aCx, JS::Handle<JS::Value> aArgument, |
|
218 JS::MutableHandle<JS::Value> aValue) |
|
219 { |
|
220 aValue.set(aArgument); |
|
221 return MaybeWrapValue(aCx, aValue); |
|
222 } |
|
223 |
|
224 // Accept nsresult, for use in rejections, and create an XPCOM |
|
225 // exception object representing that nsresult. |
|
226 bool |
|
227 ToJSValue(JSContext* aCx, |
|
228 nsresult aArgument, |
|
229 JS::MutableHandle<JS::Value> aValue); |
|
230 |
|
231 // Accept arrays of other things we accept |
|
232 template <typename T> |
|
233 bool |
|
234 ToJSValue(JSContext* aCx, |
|
235 T* aArguments, |
|
236 size_t aLength, |
|
237 JS::MutableHandle<JS::Value> aValue) |
|
238 { |
|
239 // Make sure we're called in a compartment |
|
240 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx)); |
|
241 |
|
242 JS::AutoValueVector v(aCx); |
|
243 if (!v.resize(aLength)) { |
|
244 return false; |
|
245 } |
|
246 for (size_t i = 0; i < aLength; ++i) { |
|
247 if (!ToJSValue(aCx, aArguments[i], v.handleAt(i))) { |
|
248 return false; |
|
249 } |
|
250 } |
|
251 JSObject* arrayObj = JS_NewArrayObject(aCx, v); |
|
252 if (!arrayObj) { |
|
253 return false; |
|
254 } |
|
255 aValue.setObject(*arrayObj); |
|
256 return true; |
|
257 } |
|
258 |
|
259 template <typename T> |
|
260 bool |
|
261 ToJSValue(JSContext* aCx, |
|
262 const nsTArray<T>& aArgument, |
|
263 JS::MutableHandle<JS::Value> aValue) |
|
264 { |
|
265 return ToJSValue(aCx, aArgument.Elements(), |
|
266 aArgument.Length(), aValue); |
|
267 } |
|
268 |
|
269 template <typename T> |
|
270 bool |
|
271 ToJSValue(JSContext* aCx, |
|
272 const FallibleTArray<T>& aArgument, |
|
273 JS::MutableHandle<JS::Value> aValue) |
|
274 { |
|
275 return ToJSValue(aCx, aArgument.Elements(), |
|
276 aArgument.Length(), aValue); |
|
277 } |
|
278 |
|
279 template <typename T, int N> |
|
280 bool |
|
281 ToJSValue(JSContext* aCx, |
|
282 const T(&aArgument)[N], |
|
283 JS::MutableHandle<JS::Value> aValue) |
|
284 { |
|
285 return ToJSValue(aCx, aArgument, N, aValue); |
|
286 } |
|
287 |
|
288 } // namespace dom |
|
289 } // namespace mozilla |
|
290 |
|
291 #endif /* mozilla_dom_ToJSValue_h */ |