Line data Source code
1 : /* THIS FILE IS AUTOGENERATED FROM AudioBuffer.webidl BY Codegen.py - DO NOT EDIT */
2 :
3 : #include "AtomList.h"
4 : #include "AudioBufferBinding.h"
5 : #include "WrapperFactory.h"
6 : #include "jsfriendapi.h"
7 : #include "mozilla/FloatingPoint.h"
8 : #include "mozilla/OwningNonNull.h"
9 : #include "mozilla/Preferences.h"
10 : #include "mozilla/dom/AudioBuffer.h"
11 : #include "mozilla/dom/BindingUtils.h"
12 : #include "mozilla/dom/DOMJSClass.h"
13 : #include "mozilla/dom/NonRefcountedDOMObject.h"
14 : #include "mozilla/dom/PrimitiveConversions.h"
15 : #include "mozilla/dom/ScriptSettings.h"
16 : #include "mozilla/dom/SimpleGlobalObject.h"
17 : #include "mozilla/dom/TypedArray.h"
18 : #include "mozilla/dom/XrayExpandoClass.h"
19 :
20 : namespace mozilla {
21 : namespace dom {
22 :
23 :
24 0 : AudioBufferOptions::AudioBufferOptions()
25 : {
26 : // Safe to pass a null context if we pass a null value
27 0 : Init(nullptr, JS::NullHandleValue);
28 0 : }
29 :
30 :
31 :
32 : bool
33 0 : AudioBufferOptions::InitIds(JSContext* cx, AudioBufferOptionsAtoms* atomsCache)
34 : {
35 0 : MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
36 :
37 : // Initialize these in reverse order so that any failure leaves the first one
38 : // uninitialized.
39 0 : if (!atomsCache->sampleRate_id.init(cx, "sampleRate") ||
40 0 : !atomsCache->numberOfChannels_id.init(cx, "numberOfChannels") ||
41 0 : !atomsCache->length_id.init(cx, "length")) {
42 0 : return false;
43 : }
44 0 : return true;
45 : }
46 :
47 : bool
48 0 : AudioBufferOptions::Init(JSContext* cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
49 : {
50 : // Passing a null JSContext is OK only if we're initing from null,
51 : // Since in that case we will not have to do any property gets
52 : // Also evaluate isNullOrUndefined in order to avoid false-positive
53 : // checkers by static analysis tools
54 0 : MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
55 0 : AudioBufferOptionsAtoms* atomsCache = nullptr;
56 0 : if (cx) {
57 0 : atomsCache = GetAtomCache<AudioBufferOptionsAtoms>(cx);
58 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
59 0 : return false;
60 : }
61 : }
62 :
63 0 : if (!IsConvertibleToDictionary(val)) {
64 0 : return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
65 : }
66 :
67 0 : bool isNull = val.isNullOrUndefined();
68 : // We only need these if !isNull, in which case we have |cx|.
69 0 : Maybe<JS::Rooted<JSObject *> > object;
70 0 : Maybe<JS::Rooted<JS::Value> > temp;
71 0 : if (!isNull) {
72 0 : MOZ_ASSERT(cx);
73 0 : object.emplace(cx, &val.toObject());
74 0 : temp.emplace(cx);
75 : }
76 0 : if (!isNull) {
77 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->length_id, temp.ptr())) {
78 0 : return false;
79 : }
80 : }
81 0 : if (!isNull && !temp->isUndefined()) {
82 0 : if (!ValueToPrimitive<uint32_t, eDefault>(cx, temp.ref(), &mLength)) {
83 0 : return false;
84 : }
85 0 : mIsAnyMemberPresent = true;
86 0 : } else if (cx) {
87 : // Don't error out if we have no cx. In that
88 : // situation the caller is default-constructing us and we'll
89 : // just assume they know what they're doing.
90 0 : return ThrowErrorMessage(cx, MSG_MISSING_REQUIRED_DICTIONARY_MEMBER,
91 0 : "'length' member of AudioBufferOptions");
92 : }
93 :
94 0 : if (!isNull) {
95 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->numberOfChannels_id, temp.ptr())) {
96 0 : return false;
97 : }
98 : }
99 0 : if (!isNull && !temp->isUndefined()) {
100 0 : if (!ValueToPrimitive<uint32_t, eDefault>(cx, temp.ref(), &mNumberOfChannels)) {
101 0 : return false;
102 : }
103 : } else {
104 0 : mNumberOfChannels = 1U;
105 : }
106 0 : mIsAnyMemberPresent = true;
107 :
108 0 : if (!isNull) {
109 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->sampleRate_id, temp.ptr())) {
110 0 : return false;
111 : }
112 : }
113 0 : if (!isNull && !temp->isUndefined()) {
114 0 : if (!ValueToPrimitive<float, eDefault>(cx, temp.ref(), &mSampleRate)) {
115 0 : return false;
116 0 : } else if (!mozilla::IsFinite(mSampleRate)) {
117 0 : ThrowErrorMessage(cx, MSG_NOT_FINITE, "'sampleRate' member of AudioBufferOptions");
118 0 : return false;
119 : }
120 0 : mIsAnyMemberPresent = true;
121 0 : } else if (cx) {
122 : // Don't error out if we have no cx. In that
123 : // situation the caller is default-constructing us and we'll
124 : // just assume they know what they're doing.
125 0 : return ThrowErrorMessage(cx, MSG_MISSING_REQUIRED_DICTIONARY_MEMBER,
126 0 : "'sampleRate' member of AudioBufferOptions");
127 : }
128 0 : return true;
129 : }
130 :
131 : bool
132 0 : AudioBufferOptions::Init(const nsAString& aJSON)
133 : {
134 0 : AutoJSAPI jsapi;
135 0 : JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
136 0 : if (!cleanGlobal) {
137 0 : return false;
138 : }
139 0 : if (!jsapi.Init(cleanGlobal)) {
140 0 : return false;
141 : }
142 0 : JSContext* cx = jsapi.cx();
143 0 : JS::Rooted<JS::Value> json(cx);
144 0 : bool ok = ParseJSON(cx, aJSON, &json);
145 0 : NS_ENSURE_TRUE(ok, false);
146 0 : return Init(cx, json);
147 : }
148 :
149 : bool
150 0 : AudioBufferOptions::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
151 : {
152 0 : AudioBufferOptionsAtoms* atomsCache = GetAtomCache<AudioBufferOptionsAtoms>(cx);
153 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
154 0 : return false;
155 : }
156 :
157 0 : JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
158 0 : if (!obj) {
159 0 : return false;
160 : }
161 0 : rval.set(JS::ObjectValue(*obj));
162 :
163 : do {
164 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
165 0 : JS::Rooted<JS::Value> temp(cx);
166 0 : uint32_t const & currentValue = mLength;
167 0 : temp.setNumber(currentValue);
168 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->length_id, temp, JSPROP_ENUMERATE)) {
169 0 : return false;
170 : }
171 0 : break;
172 : } while(0);
173 :
174 : do {
175 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
176 0 : JS::Rooted<JS::Value> temp(cx);
177 0 : uint32_t const & currentValue = mNumberOfChannels;
178 0 : temp.setNumber(currentValue);
179 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->numberOfChannels_id, temp, JSPROP_ENUMERATE)) {
180 0 : return false;
181 : }
182 0 : break;
183 : } while(0);
184 :
185 : do {
186 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
187 0 : JS::Rooted<JS::Value> temp(cx);
188 0 : float const & currentValue = mSampleRate;
189 0 : temp.set(JS_NumberValue(double(currentValue)));
190 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->sampleRate_id, temp, JSPROP_ENUMERATE)) {
191 0 : return false;
192 : }
193 0 : break;
194 : } while(0);
195 :
196 0 : return true;
197 : }
198 :
199 : bool
200 0 : AudioBufferOptions::ToJSON(nsAString& aJSON) const
201 : {
202 0 : AutoJSAPI jsapi;
203 0 : jsapi.Init();
204 0 : JSContext *cx = jsapi.cx();
205 : // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
206 : // because we'll only be creating objects, in ways that have no
207 : // side-effects, followed by a call to JS::ToJSONMaybeSafely,
208 : // which likewise guarantees no side-effects for the sorts of
209 : // things we will pass it.
210 0 : JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
211 0 : JS::Rooted<JS::Value> val(cx);
212 0 : if (!ToObjectInternal(cx, &val)) {
213 0 : return false;
214 : }
215 0 : JS::Rooted<JSObject*> obj(cx, &val.toObject());
216 0 : return StringifyToJSON(cx, obj, aJSON);
217 : }
218 :
219 : void
220 0 : AudioBufferOptions::TraceDictionary(JSTracer* trc)
221 : {
222 0 : }
223 :
224 : AudioBufferOptions&
225 0 : AudioBufferOptions::operator=(const AudioBufferOptions& aOther)
226 : {
227 0 : mLength = aOther.mLength;
228 0 : mNumberOfChannels = aOther.mNumberOfChannels;
229 0 : mSampleRate = aOther.mSampleRate;
230 0 : return *this;
231 : }
232 :
233 : namespace binding_detail {
234 : } // namespace binding_detail
235 :
236 :
237 : namespace AudioBufferBinding {
238 :
239 : static bool
240 0 : get_sampleRate(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioBuffer* self, JSJitGetterCallArgs args)
241 : {
242 0 : float result(self->SampleRate());
243 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
244 0 : args.rval().set(JS_NumberValue(double(result)));
245 0 : return true;
246 : }
247 :
248 : static const JSJitInfo sampleRate_getterinfo = {
249 : { (JSJitGetterOp)get_sampleRate },
250 : { prototypes::id::AudioBuffer },
251 : { PrototypeTraits<prototypes::id::AudioBuffer>::Depth },
252 : JSJitInfo::Getter,
253 : JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */
254 : JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */
255 : true, /* isInfallible. False in setters. */
256 : false, /* isMovable. Not relevant for setters. */
257 : false, /* isEliminatable. Not relevant for setters. */
258 : false, /* isAlwaysInSlot. Only relevant for getters. */
259 : false, /* isLazilyCachedInSlot. Only relevant for getters. */
260 : false, /* isTypedMethod. Only relevant for methods. */
261 : 0 /* Reserved slot index, if we're stored in a slot, else 0. */
262 : };
263 : static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
264 : static_assert(0 < 1, "There is no slot for us");
265 :
266 : static bool
267 0 : get_length(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioBuffer* self, JSJitGetterCallArgs args)
268 : {
269 0 : uint32_t result(self->Length());
270 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
271 0 : args.rval().setNumber(result);
272 0 : return true;
273 : }
274 :
275 : static const JSJitInfo length_getterinfo = {
276 : { (JSJitGetterOp)get_length },
277 : { prototypes::id::AudioBuffer },
278 : { PrototypeTraits<prototypes::id::AudioBuffer>::Depth },
279 : JSJitInfo::Getter,
280 : JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */
281 : JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */
282 : true, /* isInfallible. False in setters. */
283 : false, /* isMovable. Not relevant for setters. */
284 : false, /* isEliminatable. Not relevant for setters. */
285 : false, /* isAlwaysInSlot. Only relevant for getters. */
286 : false, /* isLazilyCachedInSlot. Only relevant for getters. */
287 : false, /* isTypedMethod. Only relevant for methods. */
288 : 0 /* Reserved slot index, if we're stored in a slot, else 0. */
289 : };
290 : static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
291 : static_assert(0 < 1, "There is no slot for us");
292 :
293 : static bool
294 0 : get_duration(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioBuffer* self, JSJitGetterCallArgs args)
295 : {
296 0 : double result(self->Duration());
297 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
298 0 : args.rval().set(JS_NumberValue(double(result)));
299 0 : return true;
300 : }
301 :
302 : static const JSJitInfo duration_getterinfo = {
303 : { (JSJitGetterOp)get_duration },
304 : { prototypes::id::AudioBuffer },
305 : { PrototypeTraits<prototypes::id::AudioBuffer>::Depth },
306 : JSJitInfo::Getter,
307 : JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */
308 : JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */
309 : true, /* isInfallible. False in setters. */
310 : false, /* isMovable. Not relevant for setters. */
311 : false, /* isEliminatable. Not relevant for setters. */
312 : false, /* isAlwaysInSlot. Only relevant for getters. */
313 : false, /* isLazilyCachedInSlot. Only relevant for getters. */
314 : false, /* isTypedMethod. Only relevant for methods. */
315 : 0 /* Reserved slot index, if we're stored in a slot, else 0. */
316 : };
317 : static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
318 : static_assert(0 < 1, "There is no slot for us");
319 :
320 : static bool
321 0 : get_numberOfChannels(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioBuffer* self, JSJitGetterCallArgs args)
322 : {
323 0 : uint32_t result(self->NumberOfChannels());
324 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
325 0 : args.rval().setNumber(result);
326 0 : return true;
327 : }
328 :
329 : static const JSJitInfo numberOfChannels_getterinfo = {
330 : { (JSJitGetterOp)get_numberOfChannels },
331 : { prototypes::id::AudioBuffer },
332 : { PrototypeTraits<prototypes::id::AudioBuffer>::Depth },
333 : JSJitInfo::Getter,
334 : JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */
335 : JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */
336 : true, /* isInfallible. False in setters. */
337 : false, /* isMovable. Not relevant for setters. */
338 : false, /* isEliminatable. Not relevant for setters. */
339 : false, /* isAlwaysInSlot. Only relevant for getters. */
340 : false, /* isLazilyCachedInSlot. Only relevant for getters. */
341 : false, /* isTypedMethod. Only relevant for methods. */
342 : 0 /* Reserved slot index, if we're stored in a slot, else 0. */
343 : };
344 : static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
345 : static_assert(0 < 1, "There is no slot for us");
346 :
347 : static bool
348 0 : getChannelData(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioBuffer* self, const JSJitMethodCallArgs& args)
349 : {
350 0 : if (MOZ_UNLIKELY(args.length() < 1)) {
351 0 : return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "AudioBuffer.getChannelData");
352 : }
353 : uint32_t arg0;
354 0 : if (!ValueToPrimitive<uint32_t, eDefault>(cx, args[0], &arg0)) {
355 0 : return false;
356 : }
357 0 : binding_detail::FastErrorResult rv;
358 0 : JS::Rooted<JSObject*> result(cx);
359 0 : self->GetChannelData(cx, arg0, &result, rv);
360 0 : if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
361 0 : return false;
362 : }
363 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
364 0 : JS::ExposeObjectToActiveJS(result);
365 0 : args.rval().setObject(*result);
366 0 : if (!MaybeWrapNonDOMObjectValue(cx, args.rval())) {
367 0 : return false;
368 : }
369 0 : return true;
370 : }
371 :
372 : static const JSJitInfo getChannelData_methodinfo = {
373 : { (JSJitGetterOp)getChannelData },
374 : { prototypes::id::AudioBuffer },
375 : { PrototypeTraits<prototypes::id::AudioBuffer>::Depth },
376 : JSJitInfo::Method,
377 : JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */
378 : JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */
379 : false, /* isInfallible. False in setters. */
380 : false, /* isMovable. Not relevant for setters. */
381 : false, /* isEliminatable. Not relevant for setters. */
382 : false, /* isAlwaysInSlot. Only relevant for getters. */
383 : false, /* isLazilyCachedInSlot. Only relevant for getters. */
384 : false, /* isTypedMethod. Only relevant for methods. */
385 : 0 /* Reserved slot index, if we're stored in a slot, else 0. */
386 : };
387 : static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
388 : static_assert(0 < 1, "There is no slot for us");
389 :
390 : static bool
391 0 : copyFromChannel(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioBuffer* self, const JSJitMethodCallArgs& args)
392 : {
393 0 : if (MOZ_UNLIKELY(args.length() < 2)) {
394 0 : return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "AudioBuffer.copyFromChannel");
395 : }
396 0 : RootedTypedArray<Float32Array> arg0(cx);
397 0 : if (args[0].isObject()) {
398 0 : if (!arg0.Init(&args[0].toObject())) {
399 0 : ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "Argument 1 of AudioBuffer.copyFromChannel", "Float32Array");
400 0 : return false;
401 : }
402 : } else {
403 0 : ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of AudioBuffer.copyFromChannel");
404 0 : return false;
405 : }
406 : int32_t arg1;
407 0 : if (!ValueToPrimitive<int32_t, eDefault>(cx, args[1], &arg1)) {
408 0 : return false;
409 : }
410 : uint32_t arg2;
411 0 : if (args.hasDefined(2)) {
412 0 : if (!ValueToPrimitive<uint32_t, eDefault>(cx, args[2], &arg2)) {
413 0 : return false;
414 : }
415 : } else {
416 0 : arg2 = 0U;
417 : }
418 0 : binding_detail::FastErrorResult rv;
419 0 : self->CopyFromChannel(Constify(arg0), arg1, arg2, rv);
420 0 : if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
421 0 : return false;
422 : }
423 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
424 0 : args.rval().setUndefined();
425 0 : return true;
426 : }
427 :
428 : static const JSJitInfo copyFromChannel_methodinfo = {
429 : { (JSJitGetterOp)copyFromChannel },
430 : { prototypes::id::AudioBuffer },
431 : { PrototypeTraits<prototypes::id::AudioBuffer>::Depth },
432 : JSJitInfo::Method,
433 : JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */
434 : JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */
435 : false, /* isInfallible. False in setters. */
436 : false, /* isMovable. Not relevant for setters. */
437 : false, /* isEliminatable. Not relevant for setters. */
438 : false, /* isAlwaysInSlot. Only relevant for getters. */
439 : false, /* isLazilyCachedInSlot. Only relevant for getters. */
440 : false, /* isTypedMethod. Only relevant for methods. */
441 : 0 /* Reserved slot index, if we're stored in a slot, else 0. */
442 : };
443 : static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
444 : static_assert(0 < 1, "There is no slot for us");
445 :
446 : static bool
447 0 : copyToChannel(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::AudioBuffer* self, const JSJitMethodCallArgs& args)
448 : {
449 0 : if (MOZ_UNLIKELY(args.length() < 2)) {
450 0 : return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "AudioBuffer.copyToChannel");
451 : }
452 0 : RootedTypedArray<Float32Array> arg0(cx);
453 0 : if (args[0].isObject()) {
454 0 : if (!arg0.Init(&args[0].toObject())) {
455 0 : ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "Argument 1 of AudioBuffer.copyToChannel", "Float32Array");
456 0 : return false;
457 : }
458 : } else {
459 0 : ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of AudioBuffer.copyToChannel");
460 0 : return false;
461 : }
462 : int32_t arg1;
463 0 : if (!ValueToPrimitive<int32_t, eDefault>(cx, args[1], &arg1)) {
464 0 : return false;
465 : }
466 : uint32_t arg2;
467 0 : if (args.hasDefined(2)) {
468 0 : if (!ValueToPrimitive<uint32_t, eDefault>(cx, args[2], &arg2)) {
469 0 : return false;
470 : }
471 : } else {
472 0 : arg2 = 0U;
473 : }
474 0 : binding_detail::FastErrorResult rv;
475 0 : self->CopyToChannel(cx, Constify(arg0), arg1, arg2, rv);
476 0 : if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
477 0 : return false;
478 : }
479 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
480 0 : args.rval().setUndefined();
481 0 : return true;
482 : }
483 :
484 : static const JSJitInfo copyToChannel_methodinfo = {
485 : { (JSJitGetterOp)copyToChannel },
486 : { prototypes::id::AudioBuffer },
487 : { PrototypeTraits<prototypes::id::AudioBuffer>::Depth },
488 : JSJitInfo::Method,
489 : JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */
490 : JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */
491 : false, /* isInfallible. False in setters. */
492 : false, /* isMovable. Not relevant for setters. */
493 : false, /* isEliminatable. Not relevant for setters. */
494 : false, /* isAlwaysInSlot. Only relevant for getters. */
495 : false, /* isLazilyCachedInSlot. Only relevant for getters. */
496 : false, /* isTypedMethod. Only relevant for methods. */
497 : 0 /* Reserved slot index, if we're stored in a slot, else 0. */
498 : };
499 : static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
500 : static_assert(0 < 1, "There is no slot for us");
501 :
502 : static bool
503 0 : _addProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> val)
504 : {
505 0 : mozilla::dom::AudioBuffer* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::AudioBuffer>(obj);
506 : // We don't want to preserve if we don't have a wrapper, and we
507 : // obviously can't preserve if we're not initialized.
508 0 : if (self && self->GetWrapperPreserveColor()) {
509 0 : PreserveWrapper(self);
510 : }
511 0 : return true;
512 : }
513 :
514 : static void
515 0 : _finalize(js::FreeOp* fop, JSObject* obj)
516 : {
517 0 : mozilla::dom::AudioBuffer* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::AudioBuffer>(obj);
518 0 : if (self) {
519 0 : ClearWrapper(self, self, obj);
520 0 : AddForDeferredFinalization<mozilla::dom::AudioBuffer>(self);
521 : }
522 0 : }
523 :
524 : static void
525 0 : _objectMoved(JSObject* obj, const JSObject* old)
526 : {
527 0 : mozilla::dom::AudioBuffer* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::AudioBuffer>(obj);
528 0 : if (self) {
529 0 : UpdateWrapper(self, self, obj, old);
530 : }
531 0 : }
532 :
533 : // We deliberately use brace-elision to make Visual Studio produce better initalization code.
534 : #if defined(__clang__)
535 : #pragma clang diagnostic push
536 : #pragma clang diagnostic ignored "-Wmissing-braces"
537 : #endif
538 : static const JSFunctionSpec sMethods_specs[] = {
539 : JS_FNSPEC("getChannelData", GenericBindingMethod, reinterpret_cast<const JSJitInfo*>(&getChannelData_methodinfo), 1, JSPROP_ENUMERATE, nullptr),
540 : JS_FNSPEC("copyFromChannel", GenericBindingMethod, reinterpret_cast<const JSJitInfo*>(©FromChannel_methodinfo), 2, JSPROP_ENUMERATE, nullptr),
541 : JS_FNSPEC("copyToChannel", GenericBindingMethod, reinterpret_cast<const JSJitInfo*>(©ToChannel_methodinfo), 2, JSPROP_ENUMERATE, nullptr),
542 : JS_FS_END
543 : };
544 : #if defined(__clang__)
545 : #pragma clang diagnostic pop
546 : #endif
547 :
548 :
549 : // Can't be const because the pref-enabled boolean needs to be writable
550 : static Prefable<const JSFunctionSpec> sMethods[] = {
551 : { nullptr, &sMethods_specs[0] },
552 : { nullptr, nullptr }
553 : };
554 :
555 : static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
556 : "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
557 : static_assert(3 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
558 : "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
559 :
560 : // We deliberately use brace-elision to make Visual Studio produce better initalization code.
561 : #if defined(__clang__)
562 : #pragma clang diagnostic push
563 : #pragma clang diagnostic ignored "-Wmissing-braces"
564 : #endif
565 : static const JSPropertySpec sAttributes_specs[] = {
566 : { "sampleRate", JSPROP_SHARED | JSPROP_ENUMERATE, GenericBindingGetter, &sampleRate_getterinfo, nullptr, nullptr },
567 : { "length", JSPROP_SHARED | JSPROP_ENUMERATE, GenericBindingGetter, &length_getterinfo, nullptr, nullptr },
568 : { "duration", JSPROP_SHARED | JSPROP_ENUMERATE, GenericBindingGetter, &duration_getterinfo, nullptr, nullptr },
569 : { "numberOfChannels", JSPROP_SHARED | JSPROP_ENUMERATE, GenericBindingGetter, &numberOfChannels_getterinfo, nullptr, nullptr },
570 : { nullptr, 0, nullptr, nullptr, nullptr, nullptr }
571 : };
572 : #if defined(__clang__)
573 : #pragma clang diagnostic pop
574 : #endif
575 :
576 :
577 : // Can't be const because the pref-enabled boolean needs to be writable
578 : static Prefable<const JSPropertySpec> sAttributes[] = {
579 : { nullptr, &sAttributes_specs[0] },
580 : { nullptr, nullptr }
581 : };
582 :
583 : static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
584 : "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
585 : static_assert(4 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
586 : "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
587 :
588 :
589 : static uint16_t sNativeProperties_sortedPropertyIndices[7];
590 : static PropertyInfo sNativeProperties_propertyInfos[7];
591 :
592 : static const NativePropertiesN<2> sNativeProperties = {
593 : false, 0,
594 : false, 0,
595 : true, 0 /* sMethods */,
596 : true, 1 /* sAttributes */,
597 : false, 0,
598 : false, 0,
599 : false, 0,
600 : -1,
601 : 7,
602 : sNativeProperties_sortedPropertyIndices,
603 : {
604 : { sMethods, &sNativeProperties_propertyInfos[0] },
605 : { sAttributes, &sNativeProperties_propertyInfos[3] }
606 : }
607 : };
608 : static_assert(7 < 1ull << CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount),
609 : "We have a property info count that is oversized");
610 :
611 : static bool
612 0 : _constructor(JSContext* cx, unsigned argc, JS::Value* vp)
613 : {
614 0 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
615 0 : JS::Rooted<JSObject*> obj(cx, &args.callee());
616 0 : if (!args.isConstructing()) {
617 : // XXXbz wish I could get the name from the callee instead of
618 : // Adding more relocations
619 0 : return ThrowConstructorWithoutNew(cx, "AudioBuffer");
620 : }
621 :
622 0 : GlobalObject global(cx, obj);
623 0 : if (global.Failed()) {
624 0 : return false;
625 : }
626 :
627 0 : JS::Rooted<JSObject*> desiredProto(cx);
628 0 : if (!GetDesiredProto(cx, args, &desiredProto)) {
629 0 : return false;
630 : }
631 :
632 0 : if (MOZ_UNLIKELY(args.length() < 1)) {
633 0 : return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "AudioBuffer");
634 : }
635 0 : bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);
636 0 : binding_detail::FastAudioBufferOptions arg0;
637 0 : if (!arg0.Init(cx, args[0], "Argument 1 of AudioBuffer.constructor", false)) {
638 0 : return false;
639 : }
640 0 : Maybe<JSAutoCompartment> ac;
641 0 : if (objIsXray) {
642 0 : obj = js::CheckedUnwrap(obj);
643 0 : if (!obj) {
644 0 : return false;
645 : }
646 0 : ac.emplace(cx, obj);
647 0 : if (!JS_WrapObject(cx, &desiredProto)) {
648 0 : return false;
649 : }
650 : }
651 0 : binding_detail::FastErrorResult rv;
652 0 : auto result(StrongOrRawPtr<mozilla::dom::AudioBuffer>(mozilla::dom::AudioBuffer::Constructor(global, Constify(arg0), rv)));
653 0 : if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
654 0 : return false;
655 : }
656 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
657 : static_assert(!IsPointer<decltype(result)>::value,
658 : "NewObject implies that we need to keep the object alive with a strong reference.");
659 0 : if (!GetOrCreateDOMReflector(cx, result, args.rval(), desiredProto)) {
660 0 : MOZ_ASSERT(true || JS_IsExceptionPending(cx));
661 0 : return false;
662 : }
663 0 : return true;
664 : }
665 :
666 : static const js::ClassOps sInterfaceObjectClassOps = {
667 : nullptr, /* addProperty */
668 : nullptr, /* delProperty */
669 : nullptr, /* getProperty */
670 : nullptr, /* setProperty */
671 : nullptr, /* enumerate */
672 : nullptr, /* newEnumerate */
673 : nullptr, /* resolve */
674 : nullptr, /* mayResolve */
675 : nullptr, /* finalize */
676 : _constructor, /* call */
677 : nullptr, /* hasInstance */
678 : _constructor, /* construct */
679 : nullptr, /* trace */
680 : };
681 :
682 : static const DOMIfaceAndProtoJSClass sInterfaceObjectClass = {
683 : {
684 : "Function",
685 : JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_SLOTS_BASE),
686 : &sInterfaceObjectClassOps,
687 : JS_NULL_CLASS_SPEC,
688 : JS_NULL_CLASS_EXT,
689 : &sInterfaceObjectClassObjectOps
690 : },
691 : eInterface,
692 : true,
693 : prototypes::id::AudioBuffer,
694 : PrototypeTraits<prototypes::id::AudioBuffer>::Depth,
695 : sNativePropertyHooks,
696 : "function AudioBuffer() {\n [native code]\n}",
697 : JS::GetRealmFunctionPrototype
698 : };
699 :
700 : static const DOMIfaceAndProtoJSClass sPrototypeClass = {
701 : {
702 : "AudioBufferPrototype",
703 : JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE),
704 : JS_NULL_CLASS_OPS,
705 : JS_NULL_CLASS_SPEC,
706 : JS_NULL_CLASS_EXT,
707 : JS_NULL_OBJECT_OPS
708 : },
709 : eInterfacePrototype,
710 : false,
711 : prototypes::id::AudioBuffer,
712 : PrototypeTraits<prototypes::id::AudioBuffer>::Depth,
713 : sNativePropertyHooks,
714 : "[object AudioBufferPrototype]",
715 : JS::GetRealmObjectPrototype
716 : };
717 :
718 : bool
719 0 : ConstructorEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj)
720 : {
721 : static bool sPrefValue;
722 : static bool sPrefCacheSetUp = false;
723 0 : if (!sPrefCacheSetUp) {
724 0 : sPrefCacheSetUp = true;
725 0 : Preferences::AddBoolVarCache(&sPrefValue, "dom.webaudio.enabled");
726 : }
727 :
728 0 : return sPrefValue;
729 : }
730 :
731 : JSObject*
732 0 : DefineDOMInterface(JSContext* aCx, JS::Handle<JSObject*> aGlobal, JS::Handle<jsid> id, bool aDefineOnGlobal)
733 : {
734 0 : return GetConstructorObjectHandle(aCx, aDefineOnGlobal);
735 : }
736 :
737 : static const js::ClassOps sClassOps = {
738 : _addProperty, /* addProperty */
739 : nullptr, /* delProperty */
740 : nullptr, /* getProperty */
741 : nullptr, /* setProperty */
742 : nullptr, /* enumerate */
743 : nullptr, /* newEnumerate */
744 : nullptr, /* resolve */
745 : nullptr, /* mayResolve */
746 : _finalize, /* finalize */
747 : nullptr, /* call */
748 : nullptr, /* hasInstance */
749 : nullptr, /* construct */
750 : nullptr, /* trace */
751 : };
752 :
753 : static const js::ClassExtension sClassExtension = {
754 : nullptr, /* weakmapKeyDelegateOp */
755 : _objectMoved /* objectMovedOp */
756 : };
757 :
758 : static const DOMJSClass sClass = {
759 : { "AudioBuffer",
760 : JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1),
761 : &sClassOps,
762 : JS_NULL_CLASS_SPEC,
763 : &sClassExtension,
764 : JS_NULL_OBJECT_OPS
765 : },
766 : { prototypes::id::AudioBuffer, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count },
767 : IsBaseOf<nsISupports, mozilla::dom::AudioBuffer >::value,
768 : sNativePropertyHooks,
769 : FindAssociatedGlobalForNative<mozilla::dom::AudioBuffer>::Get,
770 : GetProtoObjectHandle,
771 : GetCCParticipant<mozilla::dom::AudioBuffer>::Get()
772 : };
773 : static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS,
774 : "Must have the right minimal number of reserved slots.");
775 : static_assert(1 >= 1,
776 : "Must have enough reserved slots.");
777 :
778 : const JSClass*
779 0 : GetJSClass()
780 : {
781 0 : return sClass.ToJSClass();
782 : }
783 :
784 : bool
785 0 : Wrap(JSContext* aCx, mozilla::dom::AudioBuffer* aObject, nsWrapperCache* aCache, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
786 : {
787 : MOZ_ASSERT(static_cast<mozilla::dom::AudioBuffer*>(aObject) ==
788 : reinterpret_cast<mozilla::dom::AudioBuffer*>(aObject),
789 : "Multiple inheritance for mozilla::dom::AudioBuffer is broken.");
790 0 : MOZ_ASSERT(ToSupportsIsCorrect(aObject));
791 0 : MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
792 0 : MOZ_ASSERT(!aCache->GetWrapper(),
793 : "You should probably not be using Wrap() directly; use "
794 : "GetOrCreateDOMReflector instead");
795 :
796 0 : MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
797 : "nsISupports must be on our primary inheritance chain");
798 :
799 0 : JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
800 0 : if (!global) {
801 0 : return false;
802 : }
803 0 : MOZ_ASSERT(JS_IsGlobalObject(global));
804 0 : MOZ_ASSERT(JS::ObjectIsNotGray(global));
805 :
806 : // That might have ended up wrapping us already, due to the wonders
807 : // of XBL. Check for that, and bail out as needed.
808 0 : aReflector.set(aCache->GetWrapper());
809 0 : if (aReflector) {
810 : #ifdef DEBUG
811 0 : binding_detail::AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
812 : #endif // DEBUG
813 0 : return true;
814 : }
815 :
816 0 : JSAutoCompartment ac(aCx, global);
817 0 : JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
818 0 : if (!canonicalProto) {
819 0 : return false;
820 : }
821 0 : JS::Rooted<JSObject*> proto(aCx);
822 0 : if (aGivenProto) {
823 0 : proto = aGivenProto;
824 : // Unfortunately, while aGivenProto was in the compartment of aCx
825 : // coming in, we changed compartments to that of "parent" so may need
826 : // to wrap the proto here.
827 0 : if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) {
828 0 : if (!JS_WrapObject(aCx, &proto)) {
829 0 : return false;
830 : }
831 : }
832 : } else {
833 0 : proto = canonicalProto;
834 : }
835 :
836 0 : BindingJSObjectCreator<mozilla::dom::AudioBuffer> creator(aCx);
837 0 : creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
838 0 : if (!aReflector) {
839 0 : return false;
840 : }
841 :
842 0 : aCache->SetWrapper(aReflector);
843 0 : creator.InitializationSucceeded();
844 :
845 0 : MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
846 : aCache->GetWrapperPreserveColor() == aReflector);
847 : // If proto != canonicalProto, we have to preserve our wrapper;
848 : // otherwise we won't be able to properly recreate it later, since
849 : // we won't know what proto to use. Note that we don't check
850 : // aGivenProto here, since it's entirely possible (and even
851 : // somewhat common) to have a non-null aGivenProto which is the
852 : // same as canonicalProto.
853 0 : if (proto != canonicalProto) {
854 0 : PreserveWrapper(aObject);
855 : }
856 :
857 0 : return true;
858 : }
859 :
860 : const NativePropertyHooks sNativePropertyHooks[] = { {
861 : nullptr,
862 : nullptr,
863 : nullptr,
864 : { sNativeProperties.Upcast(), nullptr },
865 : prototypes::id::AudioBuffer,
866 : constructors::id::AudioBuffer,
867 : nullptr,
868 : &DefaultXrayExpandoObjectClass
869 : } };
870 :
871 : void
872 0 : CreateInterfaceObjects(JSContext* aCx, JS::Handle<JSObject*> aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, bool aDefineOnGlobal)
873 : {
874 0 : JS::Rooted<JSObject*> parentProto(aCx, JS::GetRealmObjectPrototype(aCx));
875 0 : if (!parentProto) {
876 0 : return;
877 : }
878 :
879 0 : JS::Rooted<JSObject*> constructorProto(aCx, JS::GetRealmFunctionPrototype(aCx));
880 0 : if (!constructorProto) {
881 0 : return;
882 : }
883 :
884 : static bool sIdsInited = false;
885 0 : if (!sIdsInited && NS_IsMainThread()) {
886 0 : if (!InitIds(aCx, sNativeProperties.Upcast())) {
887 0 : return;
888 : }
889 0 : sIdsInited = true;
890 : }
891 :
892 0 : JS::Heap<JSObject*>* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::AudioBuffer);
893 0 : JS::Heap<JSObject*>* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::AudioBuffer);
894 0 : dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
895 : &sPrototypeClass.mBase, protoCache,
896 : constructorProto, &sInterfaceObjectClass.mBase, 1, nullptr,
897 : interfaceCache,
898 : sNativeProperties.Upcast(),
899 : nullptr,
900 : "AudioBuffer", aDefineOnGlobal,
901 : nullptr,
902 0 : false);
903 : }
904 :
905 : JS::Handle<JSObject*>
906 0 : GetProtoObjectHandle(JSContext* aCx)
907 : {
908 : /* Get the interface prototype object for this class. This will create the
909 : object as needed. */
910 0 : bool aDefineOnGlobal = true;
911 :
912 : /* Make sure our global is sane. Hopefully we can remove this sometime */
913 0 : JSObject* global = JS::CurrentGlobalOrNull(aCx);
914 0 : if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
915 0 : return nullptr;
916 : }
917 :
918 : /* Check to see whether the interface objects are already installed */
919 0 : ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
920 0 : if (!protoAndIfaceCache.HasEntryInSlot(prototypes::id::AudioBuffer)) {
921 0 : JS::Rooted<JSObject*> rootedGlobal(aCx, global);
922 0 : CreateInterfaceObjects(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
923 : }
924 :
925 : /*
926 : * The object might _still_ be null, but that's OK.
927 : *
928 : * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
929 : * traced by TraceProtoAndIfaceCache() and its contents are never
930 : * changed after they have been set.
931 : *
932 : * Calling address() avoids the read read barrier that does gray
933 : * unmarking, but it's not possible for the object to be gray here.
934 : */
935 :
936 0 : const JS::Heap<JSObject*>& entrySlot = protoAndIfaceCache.EntrySlotMustExist(prototypes::id::AudioBuffer);
937 0 : MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
938 0 : return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
939 : }
940 :
941 : JS::Handle<JSObject*>
942 0 : GetConstructorObjectHandle(JSContext* aCx, bool aDefineOnGlobal)
943 : {
944 : /* Get the interface object for this class. This will create the object as
945 : needed. */
946 :
947 : /* Make sure our global is sane. Hopefully we can remove this sometime */
948 0 : JSObject* global = JS::CurrentGlobalOrNull(aCx);
949 0 : if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
950 0 : return nullptr;
951 : }
952 :
953 : /* Check to see whether the interface objects are already installed */
954 0 : ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
955 0 : if (!protoAndIfaceCache.HasEntryInSlot(constructors::id::AudioBuffer)) {
956 0 : JS::Rooted<JSObject*> rootedGlobal(aCx, global);
957 0 : CreateInterfaceObjects(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
958 : }
959 :
960 : /*
961 : * The object might _still_ be null, but that's OK.
962 : *
963 : * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
964 : * traced by TraceProtoAndIfaceCache() and its contents are never
965 : * changed after they have been set.
966 : *
967 : * Calling address() avoids the read read barrier that does gray
968 : * unmarking, but it's not possible for the object to be gray here.
969 : */
970 :
971 0 : const JS::Heap<JSObject*>& entrySlot = protoAndIfaceCache.EntrySlotMustExist(constructors::id::AudioBuffer);
972 0 : MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
973 0 : return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
974 : }
975 :
976 : JSObject*
977 0 : GetConstructorObject(JSContext* aCx)
978 : {
979 0 : return GetConstructorObjectHandle(aCx);
980 : }
981 :
982 : } // namespace AudioBufferBinding
983 :
984 :
985 :
986 : } // namespace dom
987 : } // namespace mozilla
|