1 : /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Web Workers.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * The Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2011
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Ben Turner <bent.mozilla@gmail.com> (Original Author)
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "mozilla/Util.h"
41 :
42 : #include "Events.h"
43 :
44 : #include "jsapi.h"
45 : #include "jsfriendapi.h"
46 :
47 : #include "nsTraceRefcnt.h"
48 :
49 : #include "WorkerInlines.h"
50 : #include "WorkerPrivate.h"
51 :
52 : #define PROPERTY_FLAGS \
53 : (JSPROP_ENUMERATE | JSPROP_SHARED)
54 :
55 : #define FUNCTION_FLAGS \
56 : JSPROP_ENUMERATE
57 :
58 : #define CONSTANT_FLAGS \
59 : JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY
60 :
61 : using namespace mozilla;
62 : USING_WORKERS_NAMESPACE
63 :
64 : namespace {
65 :
66 : class Event : public PrivatizableBase
67 : {
68 : static JSClass sClass;
69 : static JSClass sMainRuntimeClass;
70 :
71 : static JSPropertySpec sProperties[];
72 : static JSFunctionSpec sFunctions[];
73 : static JSPropertySpec sStaticProperties[];
74 :
75 : protected:
76 : bool mStopPropagationCalled;
77 : bool mStopImmediatePropagationCalled;
78 :
79 : public:
80 : static bool
81 147 : IsThisClass(JSClass* aClass)
82 : {
83 147 : return aClass == &sClass || aClass == &sMainRuntimeClass;
84 : }
85 :
86 : static JSObject*
87 147 : InitClass(JSContext* aCx, JSObject* aObj, bool aMainRuntime)
88 : {
89 147 : JSObject* parentProto = NULL;
90 :
91 147 : if (aMainRuntime) {
92 : jsval windowPropVal;
93 147 : if (!JS_GetProperty(aCx, aObj, sClass.name, &windowPropVal)) {
94 0 : return NULL;
95 : }
96 :
97 147 : if (!JSVAL_IS_PRIMITIVE(windowPropVal)) {
98 : jsval protoVal;
99 0 : if (!JS_GetProperty(aCx, JSVAL_TO_OBJECT(windowPropVal), "prototype",
100 0 : &protoVal)) {
101 0 : return NULL;
102 : }
103 :
104 0 : if (!JSVAL_IS_PRIMITIVE(protoVal)) {
105 0 : parentProto = JSVAL_TO_OBJECT(protoVal);
106 : }
107 : }
108 : }
109 :
110 147 : JSClass* clasp = parentProto ? &sMainRuntimeClass : &sClass;
111 :
112 : JSObject* proto = JS_InitClass(aCx, aObj, parentProto, clasp, Construct, 0,
113 : sProperties, sFunctions, sStaticProperties,
114 147 : NULL);
115 147 : if (proto && !JS_DefineProperties(aCx, proto, sStaticProperties)) {
116 0 : return NULL;
117 : }
118 :
119 147 : return proto;
120 : }
121 :
122 : static JSObject*
123 0 : Create(JSContext* aCx, JSObject* aParent, JSString* aType, bool aBubbles,
124 : bool aCancelable, bool aMainRuntime)
125 : {
126 0 : JSClass* clasp = aMainRuntime ? &sMainRuntimeClass : &sClass;
127 :
128 0 : JSObject* obj = JS_NewObject(aCx, clasp, NULL, aParent);
129 0 : if (obj) {
130 0 : Event* priv = new Event();
131 0 : SetJSPrivateSafeish(obj, priv);
132 0 : InitEventCommon(obj, priv, aType, aBubbles, aCancelable, true);
133 : }
134 0 : return obj;
135 : }
136 :
137 : static bool
138 0 : IsSupportedClass(JSObject* aEvent)
139 : {
140 0 : return !!GetPrivate(aEvent);
141 : }
142 :
143 : static void
144 0 : SetTarget(JSObject* aEvent, JSObject* aTarget)
145 : {
146 0 : JS_ASSERT(IsSupportedClass(aEvent));
147 :
148 0 : jsval target = OBJECT_TO_JSVAL(aTarget);
149 0 : JS_SetReservedSlot(aEvent, SLOT_target, target);
150 0 : JS_SetReservedSlot(aEvent, SLOT_currentTarget, target);
151 0 : }
152 :
153 : static bool
154 0 : WasCanceled(JSObject* aEvent)
155 : {
156 0 : JS_ASSERT(IsSupportedClass(aEvent));
157 :
158 0 : jsval canceled = JS_GetReservedSlot(aEvent, SLOT_defaultPrevented);
159 0 : return JSVAL_TO_BOOLEAN(canceled);
160 : }
161 :
162 : static bool
163 0 : ImmediatePropagationStopped(JSObject* aEvent)
164 : {
165 0 : Event* event = GetPrivate(aEvent);
166 0 : return event ? event->mStopImmediatePropagationCalled : false;
167 : }
168 :
169 : protected:
170 0 : Event()
171 0 : : mStopPropagationCalled(false), mStopImmediatePropagationCalled(false)
172 : {
173 0 : MOZ_COUNT_CTOR(mozilla::dom::workers::Event);
174 0 : }
175 :
176 0 : virtual ~Event()
177 0 : {
178 0 : MOZ_COUNT_DTOR(mozilla::dom::workers::Event);
179 0 : }
180 :
181 : enum {
182 : CAPTURING_PHASE = 1,
183 : AT_TARGET = 2,
184 : BUBBLING_PHASE = 3
185 : };
186 :
187 : enum SLOT {
188 : SLOT_type = 0,
189 : SLOT_target,
190 : SLOT_currentTarget,
191 : SLOT_eventPhase,
192 : SLOT_bubbles,
193 : SLOT_cancelable,
194 : SLOT_timeStamp,
195 : SLOT_defaultPrevented,
196 : SLOT_isTrusted,
197 :
198 : SLOT_COUNT,
199 : SLOT_FIRST = SLOT_type
200 : };
201 :
202 : static Event*
203 : GetPrivate(JSObject* aEvent);
204 :
205 : static Event*
206 0 : GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
207 : {
208 0 : Event* priv = GetPrivate(aObj);
209 0 : if (priv) {
210 0 : return priv;
211 : }
212 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
213 : JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
214 0 : JS_GetClass(aObj)->name);
215 0 : return NULL;
216 : }
217 :
218 : static void
219 0 : InitEventCommon(JSObject* aObj, Event* aEvent, JSString* aType,
220 : JSBool aBubbles, JSBool aCancelable, bool aIsTrusted)
221 : {
222 0 : aEvent->mStopPropagationCalled = false;
223 0 : aEvent->mStopImmediatePropagationCalled = false;
224 :
225 0 : JS_SetReservedSlot(aObj, SLOT_type, STRING_TO_JSVAL(aType));
226 0 : JS_SetReservedSlot(aObj, SLOT_target, JSVAL_NULL);
227 0 : JS_SetReservedSlot(aObj, SLOT_currentTarget, JSVAL_NULL);
228 0 : JS_SetReservedSlot(aObj, SLOT_eventPhase, INT_TO_JSVAL(CAPTURING_PHASE));
229 : JS_SetReservedSlot(aObj, SLOT_bubbles,
230 0 : aBubbles ? JSVAL_TRUE : JSVAL_FALSE);
231 : JS_SetReservedSlot(aObj, SLOT_cancelable,
232 0 : aCancelable ? JSVAL_TRUE : JSVAL_FALSE);
233 0 : JS_SetReservedSlot(aObj, SLOT_timeStamp, JS::NumberValue(double(JS_Now())));
234 0 : JS_SetReservedSlot(aObj, SLOT_defaultPrevented, JSVAL_FALSE);
235 : JS_SetReservedSlot(aObj, SLOT_isTrusted,
236 0 : aIsTrusted ? JSVAL_TRUE : JSVAL_FALSE);
237 0 : }
238 :
239 : private:
240 : static JSBool
241 0 : Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
242 : {
243 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
244 0 : sClass.name);
245 0 : return false;
246 : }
247 :
248 : static void
249 147 : Finalize(JSContext* aCx, JSObject* aObj)
250 : {
251 147 : JS_ASSERT(IsThisClass(JS_GetClass(aObj)));
252 147 : delete GetJSPrivateSafeish<Event>(aObj);
253 147 : }
254 :
255 : static JSBool
256 0 : GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
257 : {
258 0 : JS_ASSERT(JSID_IS_INT(aIdval));
259 :
260 0 : int32 slot = JSID_TO_INT(aIdval);
261 :
262 0 : const char*& name = sProperties[slot - SLOT_FIRST].name;
263 0 : if (!GetInstancePrivate(aCx, aObj, name)) {
264 0 : return false;
265 : }
266 :
267 0 : *aVp = JS_GetReservedSlot(aObj, slot);
268 0 : return true;
269 : }
270 :
271 : static JSBool
272 0 : GetConstant(JSContext* aCx, JSObject* aObj, jsid idval, jsval* aVp)
273 : {
274 0 : JS_ASSERT(JSID_IS_INT(idval));
275 0 : JS_ASSERT(JSID_TO_INT(idval) >= CAPTURING_PHASE &&
276 0 : JSID_TO_INT(idval) <= BUBBLING_PHASE);
277 :
278 0 : *aVp = INT_TO_JSVAL(JSID_TO_INT(idval));
279 0 : return true;
280 : }
281 :
282 : static JSBool
283 0 : StopPropagation(JSContext* aCx, unsigned aArgc, jsval* aVp)
284 : {
285 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
286 0 : if (!obj) {
287 0 : return false;
288 : }
289 :
290 0 : Event* event = GetInstancePrivate(aCx, obj, sFunctions[0].name);
291 0 : if (!event) {
292 0 : return false;
293 : }
294 :
295 0 : event->mStopPropagationCalled = true;
296 :
297 0 : return true;
298 : }
299 :
300 : static JSBool
301 0 : StopImmediatePropagation(JSContext* aCx, unsigned aArgc, jsval* aVp)
302 : {
303 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
304 0 : if (!obj) {
305 0 : return false;
306 : }
307 :
308 0 : Event* event = GetInstancePrivate(aCx, obj, sFunctions[3].name);
309 0 : if (!event) {
310 0 : return false;
311 : }
312 :
313 0 : event->mStopImmediatePropagationCalled = true;
314 :
315 0 : return true;
316 : }
317 :
318 : static JSBool
319 0 : PreventDefault(JSContext* aCx, unsigned aArgc, jsval* aVp)
320 : {
321 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
322 0 : if (!obj) {
323 0 : return false;
324 : }
325 :
326 0 : Event* event = GetInstancePrivate(aCx, obj, sFunctions[1].name);
327 0 : if (!event) {
328 0 : return false;
329 : }
330 :
331 0 : jsval cancelableVal = JS_GetReservedSlot(obj, SLOT_cancelable);
332 :
333 0 : if (JSVAL_TO_BOOLEAN(cancelableVal))
334 0 : JS_SetReservedSlot(obj, SLOT_defaultPrevented, cancelableVal);
335 0 : return true;
336 : }
337 :
338 : static JSBool
339 0 : InitEvent(JSContext* aCx, unsigned aArgc, jsval* aVp)
340 : {
341 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
342 0 : if (!obj) {
343 0 : return false;
344 : }
345 :
346 0 : Event* event = GetInstancePrivate(aCx, obj, sFunctions[2].name);
347 0 : if (!event) {
348 0 : return false;
349 : }
350 :
351 : JSString* type;
352 : JSBool bubbles, cancelable;
353 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "Sbb", &type,
354 0 : &bubbles, &cancelable)) {
355 0 : return false;
356 : }
357 :
358 0 : InitEventCommon(obj, event, type, bubbles, cancelable, false);
359 0 : return true;
360 : }
361 : };
362 :
363 : #define DECL_EVENT_CLASS(_varname, _name) \
364 : JSClass _varname = { \
365 : _name, \
366 : JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), \
367 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \
368 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize, \
369 : JSCLASS_NO_OPTIONAL_MEMBERS \
370 : };
371 :
372 : DECL_EVENT_CLASS(Event::sClass, "Event")
373 : DECL_EVENT_CLASS(Event::sMainRuntimeClass, "WorkerEvent")
374 :
375 : #undef DECL_EVENT_CLASS
376 :
377 : JSPropertySpec Event::sProperties[] = {
378 : { "type", SLOT_type, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
379 : { "target", SLOT_target, PROPERTY_FLAGS, GetProperty,
380 : js_GetterOnlyPropertyStub },
381 : { "currentTarget", SLOT_currentTarget, PROPERTY_FLAGS, GetProperty,
382 : js_GetterOnlyPropertyStub },
383 : { "eventPhase", SLOT_eventPhase, PROPERTY_FLAGS, GetProperty,
384 : js_GetterOnlyPropertyStub },
385 : { "bubbles", SLOT_bubbles, PROPERTY_FLAGS, GetProperty,
386 : js_GetterOnlyPropertyStub },
387 : { "cancelable", SLOT_cancelable, PROPERTY_FLAGS, GetProperty,
388 : js_GetterOnlyPropertyStub },
389 : { "timeStamp", SLOT_timeStamp, PROPERTY_FLAGS, GetProperty,
390 : js_GetterOnlyPropertyStub },
391 : { "defaultPrevented", SLOT_defaultPrevented, PROPERTY_FLAGS, GetProperty,
392 : js_GetterOnlyPropertyStub },
393 : { "isTrusted", SLOT_isTrusted, PROPERTY_FLAGS, GetProperty,
394 : js_GetterOnlyPropertyStub },
395 : { 0, 0, 0, NULL, NULL }
396 : };
397 :
398 : JSFunctionSpec Event::sFunctions[] = {
399 : JS_FN("stopPropagation", StopPropagation, 0, FUNCTION_FLAGS),
400 : JS_FN("preventDefault", PreventDefault, 0, FUNCTION_FLAGS),
401 : JS_FN("initEvent", InitEvent, 3, FUNCTION_FLAGS),
402 : JS_FN("stopImmediatePropagation", StopImmediatePropagation, 0, FUNCTION_FLAGS),
403 : JS_FS_END
404 : };
405 :
406 : JSPropertySpec Event::sStaticProperties[] = {
407 : { "CAPTURING_PHASE", CAPTURING_PHASE, CONSTANT_FLAGS, GetConstant, NULL },
408 : { "AT_TARGET", AT_TARGET, CONSTANT_FLAGS, GetConstant, NULL },
409 : { "BUBBLING_PHASE", BUBBLING_PHASE, CONSTANT_FLAGS, GetConstant, NULL },
410 : { 0, 0, 0, NULL, NULL }
411 : };
412 :
413 : class MessageEvent : public Event
414 : {
415 : static JSClass sClass;
416 : static JSClass sMainRuntimeClass;
417 :
418 : static JSPropertySpec sProperties[];
419 : static JSFunctionSpec sFunctions[];
420 :
421 : protected:
422 : uint64_t* mData;
423 : size_t mDataByteCount;
424 : nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
425 : bool mMainRuntime;
426 :
427 : public:
428 : static bool
429 147 : IsThisClass(JSClass* aClass)
430 : {
431 147 : return aClass == &sClass || aClass == &sMainRuntimeClass;
432 : }
433 :
434 : static JSObject*
435 147 : InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
436 : bool aMainRuntime)
437 : {
438 147 : JSClass* clasp = aMainRuntime ? &sMainRuntimeClass : &sClass;
439 :
440 : return JS_InitClass(aCx, aObj, aParentProto, clasp, Construct, 0,
441 147 : sProperties, sFunctions, NULL, NULL);
442 : }
443 :
444 : static JSObject*
445 0 : Create(JSContext* aCx, JSObject* aParent, JSAutoStructuredCloneBuffer& aData,
446 : nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects, bool aMainRuntime)
447 : {
448 0 : JSString* type = JS_InternString(aCx, "message");
449 0 : if (!type) {
450 0 : return NULL;
451 : }
452 :
453 0 : JSClass* clasp = aMainRuntime ? &sMainRuntimeClass : &sClass;
454 :
455 0 : JSObject* obj = JS_NewObject(aCx, clasp, NULL, aParent);
456 0 : if (!obj) {
457 0 : return NULL;
458 : }
459 :
460 0 : MessageEvent* priv = new MessageEvent(aMainRuntime);
461 0 : SetJSPrivateSafeish(obj, priv);
462 : InitMessageEventCommon(aCx, obj, priv, type, false, false, NULL, NULL, NULL,
463 0 : true);
464 0 : aData.steal(&priv->mData, &priv->mDataByteCount);
465 0 : priv->mClonedObjects.SwapElements(aClonedObjects);
466 :
467 0 : return obj;
468 : }
469 :
470 : protected:
471 0 : MessageEvent(bool aMainRuntime)
472 0 : : mData(NULL), mDataByteCount(0), mMainRuntime(aMainRuntime)
473 : {
474 0 : MOZ_COUNT_CTOR(mozilla::dom::workers::MessageEvent);
475 0 : }
476 :
477 0 : virtual ~MessageEvent()
478 0 : {
479 0 : MOZ_COUNT_DTOR(mozilla::dom::workers::MessageEvent);
480 0 : JS_ASSERT(!mData);
481 0 : }
482 :
483 : enum SLOT {
484 : SLOT_data = Event::SLOT_COUNT,
485 : SLOT_origin,
486 : SLOT_source,
487 :
488 : SLOT_COUNT,
489 : SLOT_FIRST = SLOT_data
490 : };
491 :
492 : private:
493 : static MessageEvent*
494 0 : GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
495 : {
496 0 : JSClass* classPtr = JS_GetClass(aObj);
497 0 : if (IsThisClass(classPtr)) {
498 0 : return GetJSPrivateSafeish<MessageEvent>(aObj);
499 : }
500 :
501 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
502 : JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
503 0 : classPtr->name);
504 0 : return NULL;
505 : }
506 :
507 : static void
508 0 : InitMessageEventCommon(JSContext* aCx, JSObject* aObj, Event* aEvent,
509 : JSString* aType, JSBool aBubbles, JSBool aCancelable,
510 : JSString* aData, JSString* aOrigin, JSObject* aSource,
511 : bool aIsTrusted)
512 : {
513 0 : jsval emptyString = JS_GetEmptyStringValue(aCx);
514 :
515 : Event::InitEventCommon(aObj, aEvent, aType, aBubbles, aCancelable,
516 0 : aIsTrusted);
517 : JS_SetReservedSlot(aObj, SLOT_data,
518 0 : aData ? STRING_TO_JSVAL(aData) : emptyString);
519 : JS_SetReservedSlot(aObj, SLOT_origin,
520 0 : aOrigin ? STRING_TO_JSVAL(aOrigin) : emptyString);
521 0 : JS_SetReservedSlot(aObj, SLOT_source, OBJECT_TO_JSVAL(aSource));
522 0 : }
523 :
524 : static JSBool
525 0 : Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
526 : {
527 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
528 0 : sClass.name);
529 0 : return false;
530 : }
531 :
532 : static void
533 147 : Finalize(JSContext* aCx, JSObject* aObj)
534 : {
535 147 : JS_ASSERT(IsThisClass(JS_GetClass(aObj)));
536 147 : MessageEvent* priv = GetJSPrivateSafeish<MessageEvent>(aObj);
537 147 : if (priv) {
538 0 : JS_free(aCx, priv->mData);
539 : #ifdef DEBUG
540 0 : priv->mData = NULL;
541 : #endif
542 0 : delete priv;
543 : }
544 147 : }
545 :
546 : static JSBool
547 0 : GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
548 : {
549 0 : JS_ASSERT(JSID_IS_INT(aIdval));
550 :
551 0 : int32 slot = JSID_TO_INT(aIdval);
552 :
553 0 : JS_ASSERT(slot >= SLOT_data && slot < SLOT_COUNT);
554 :
555 0 : const char*& name = sProperties[slot - SLOT_FIRST].name;
556 0 : MessageEvent* event = GetInstancePrivate(aCx, aObj, name);
557 0 : if (!event) {
558 0 : return false;
559 : }
560 :
561 : // Deserialize and save the data value if we can.
562 0 : if (slot == SLOT_data && event->mData) {
563 0 : JSAutoStructuredCloneBuffer buffer;
564 0 : buffer.adopt(event->mData, event->mDataByteCount);
565 :
566 0 : event->mData = NULL;
567 0 : event->mDataByteCount = 0;
568 :
569 : // Release reference to objects that were AddRef'd for
570 : // cloning into worker when array goes out of scope.
571 0 : nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
572 0 : clonedObjects.SwapElements(event->mClonedObjects);
573 :
574 : jsval data;
575 0 : if (!buffer.read(aCx, &data,
576 0 : WorkerStructuredCloneCallbacks(event->mMainRuntime))) {
577 0 : return false;
578 : }
579 0 : JS_SetReservedSlot(aObj, slot, data);
580 :
581 0 : *aVp = data;
582 0 : return true;
583 : }
584 :
585 0 : *aVp = JS_GetReservedSlot(aObj, slot);
586 0 : return true;
587 : }
588 :
589 : static JSBool
590 0 : InitMessageEvent(JSContext* aCx, unsigned aArgc, jsval* aVp)
591 : {
592 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
593 0 : if (!obj) {
594 0 : return false;
595 : }
596 :
597 0 : MessageEvent* event = GetInstancePrivate(aCx, obj, sFunctions[0].name);
598 0 : if (!event) {
599 0 : return false;
600 : }
601 :
602 : JSString* type, *data, *origin;
603 : JSBool bubbles, cancelable;
604 : JSObject* source;
605 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "SbbSSo", &type,
606 0 : &bubbles, &cancelable, &data, &origin, &source)) {
607 0 : return false;
608 : }
609 :
610 : InitMessageEventCommon(aCx, obj, event, type, bubbles, cancelable,
611 0 : data, origin, source, false);
612 0 : return true;
613 : }
614 : };
615 :
616 : #define DECL_MESSAGEEVENT_CLASS(_varname, _name) \
617 : JSClass _varname = { \
618 : _name, \
619 : JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), \
620 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \
621 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize, \
622 : JSCLASS_NO_OPTIONAL_MEMBERS \
623 : };
624 :
625 : DECL_MESSAGEEVENT_CLASS(MessageEvent::sClass, "MessageEvent")
626 : DECL_MESSAGEEVENT_CLASS(MessageEvent::sMainRuntimeClass, "WorkerMessageEvent")
627 :
628 : #undef DECL_MESSAGEEVENT_CLASS
629 :
630 : JSPropertySpec MessageEvent::sProperties[] = {
631 : { "data", SLOT_data, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
632 : { "origin", SLOT_origin, PROPERTY_FLAGS, GetProperty,
633 : js_GetterOnlyPropertyStub },
634 : { "source", SLOT_source, PROPERTY_FLAGS, GetProperty,
635 : js_GetterOnlyPropertyStub },
636 : { 0, 0, 0, NULL, NULL }
637 : };
638 :
639 : JSFunctionSpec MessageEvent::sFunctions[] = {
640 : JS_FN("initMessageEvent", InitMessageEvent, 6, FUNCTION_FLAGS),
641 : JS_FS_END
642 : };
643 :
644 : class ErrorEvent : public Event
645 : {
646 : static JSClass sClass;
647 : static JSClass sMainRuntimeClass;
648 :
649 : static JSPropertySpec sProperties[];
650 : static JSFunctionSpec sFunctions[];
651 :
652 : public:
653 : static bool
654 147 : IsThisClass(JSClass* aClass)
655 : {
656 147 : return aClass == &sClass || aClass == &sMainRuntimeClass;
657 : }
658 :
659 : static JSObject*
660 147 : InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
661 : bool aMainRuntime)
662 : {
663 147 : JSClass* clasp = aMainRuntime ? &sMainRuntimeClass : &sClass;
664 :
665 : return JS_InitClass(aCx, aObj, aParentProto, clasp, Construct, 0,
666 147 : sProperties, sFunctions, NULL, NULL);
667 : }
668 :
669 : static JSObject*
670 0 : Create(JSContext* aCx, JSObject* aParent, JSString* aMessage,
671 : JSString* aFilename, uint32 aLineNumber, bool aMainRuntime)
672 : {
673 0 : JSString* type = JS_InternString(aCx, "error");
674 0 : if (!type) {
675 0 : return NULL;
676 : }
677 :
678 0 : JSClass* clasp = aMainRuntime ? &sMainRuntimeClass : &sClass;
679 :
680 0 : JSObject* obj = JS_NewObject(aCx, clasp, NULL, aParent);
681 0 : if (!obj) {
682 0 : return NULL;
683 : }
684 :
685 0 : ErrorEvent* priv = new ErrorEvent();
686 0 : SetJSPrivateSafeish(obj, priv);
687 : InitErrorEventCommon(obj, priv, type, false, true, aMessage, aFilename,
688 0 : aLineNumber, true);
689 0 : return obj;
690 : }
691 :
692 : protected:
693 0 : ErrorEvent()
694 0 : {
695 0 : MOZ_COUNT_CTOR(mozilla::dom::workers::ErrorEvent);
696 0 : }
697 :
698 0 : virtual ~ErrorEvent()
699 0 : {
700 0 : MOZ_COUNT_DTOR(mozilla::dom::workers::ErrorEvent);
701 0 : }
702 :
703 : enum SLOT {
704 : SLOT_message = Event::SLOT_COUNT,
705 : SLOT_filename,
706 : SLOT_lineno,
707 :
708 : SLOT_COUNT,
709 : SLOT_FIRST = SLOT_message
710 : };
711 :
712 : private:
713 : static ErrorEvent*
714 0 : GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
715 : {
716 0 : JSClass* classPtr = JS_GetClass(aObj);
717 0 : if (IsThisClass(classPtr)) {
718 0 : return GetJSPrivateSafeish<ErrorEvent>(aObj);
719 : }
720 :
721 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
722 : JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
723 0 : classPtr->name);
724 0 : return NULL;
725 : }
726 :
727 : static void
728 0 : InitErrorEventCommon(JSObject* aObj, Event* aEvent, JSString* aType,
729 : JSBool aBubbles, JSBool aCancelable,
730 : JSString* aMessage, JSString* aFilename,
731 : uint32 aLineNumber, bool aIsTrusted)
732 : {
733 : Event::InitEventCommon(aObj, aEvent, aType, aBubbles, aCancelable,
734 0 : aIsTrusted);
735 0 : JS_SetReservedSlot(aObj, SLOT_message, STRING_TO_JSVAL(aMessage));
736 0 : JS_SetReservedSlot(aObj, SLOT_filename, STRING_TO_JSVAL(aFilename));
737 0 : JS_SetReservedSlot(aObj, SLOT_lineno, INT_TO_JSVAL(aLineNumber));
738 0 : }
739 :
740 : static JSBool
741 0 : Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
742 : {
743 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
744 0 : sClass.name);
745 0 : return false;
746 : }
747 :
748 : static void
749 147 : Finalize(JSContext* aCx, JSObject* aObj)
750 : {
751 147 : JS_ASSERT(IsThisClass(JS_GetClass(aObj)));
752 147 : delete GetJSPrivateSafeish<ErrorEvent>(aObj);
753 147 : }
754 :
755 : static JSBool
756 0 : GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
757 : {
758 0 : JS_ASSERT(JSID_IS_INT(aIdval));
759 :
760 0 : int32 slot = JSID_TO_INT(aIdval);
761 :
762 0 : JS_ASSERT(slot >= SLOT_message && slot < SLOT_COUNT);
763 :
764 0 : const char*& name = sProperties[slot - SLOT_FIRST].name;
765 0 : ErrorEvent* event = GetInstancePrivate(aCx, aObj, name);
766 0 : if (!event) {
767 0 : return false;
768 : }
769 :
770 0 : *aVp = JS_GetReservedSlot(aObj, slot);
771 0 : return true;
772 : }
773 :
774 : static JSBool
775 0 : InitErrorEvent(JSContext* aCx, unsigned aArgc, jsval* aVp)
776 : {
777 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
778 0 : if (!obj) {
779 0 : return false;
780 : }
781 :
782 0 : ErrorEvent* event = GetInstancePrivate(aCx, obj, sFunctions[0].name);
783 0 : if (!event) {
784 0 : return false;
785 : }
786 :
787 : JSString* type, *message, *filename;
788 : JSBool bubbles, cancelable;
789 : uint32_t lineNumber;
790 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "SbbSSu", &type,
791 : &bubbles, &cancelable, &message, &filename,
792 0 : &lineNumber)) {
793 0 : return false;
794 : }
795 :
796 : InitErrorEventCommon(obj, event, type, bubbles, cancelable, message,
797 0 : filename, lineNumber, false);
798 0 : return true;
799 : }
800 : };
801 :
802 : #define DECL_ERROREVENT_CLASS(_varname, _name) \
803 : JSClass _varname = { \
804 : _name, \
805 : JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), \
806 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \
807 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize, \
808 : JSCLASS_NO_OPTIONAL_MEMBERS \
809 : };
810 :
811 : DECL_ERROREVENT_CLASS(ErrorEvent::sClass, "ErrorEvent")
812 : DECL_ERROREVENT_CLASS(ErrorEvent::sMainRuntimeClass, "WorkerErrorEvent")
813 :
814 : #undef DECL_ERROREVENT_CLASS
815 :
816 : JSPropertySpec ErrorEvent::sProperties[] = {
817 : { "message", SLOT_message, PROPERTY_FLAGS, GetProperty,
818 : js_GetterOnlyPropertyStub },
819 : { "filename", SLOT_filename, PROPERTY_FLAGS, GetProperty,
820 : js_GetterOnlyPropertyStub },
821 : { "lineno", SLOT_lineno, PROPERTY_FLAGS, GetProperty,
822 : js_GetterOnlyPropertyStub },
823 : { 0, 0, 0, NULL, NULL }
824 : };
825 :
826 : JSFunctionSpec ErrorEvent::sFunctions[] = {
827 : JS_FN("initErrorEvent", InitErrorEvent, 6, FUNCTION_FLAGS),
828 : JS_FS_END
829 : };
830 :
831 : class ProgressEvent : public Event
832 : {
833 : static JSClass sClass;
834 : static JSPropertySpec sProperties[];
835 : static JSFunctionSpec sFunctions[];
836 :
837 : public:
838 : static JSClass*
839 0 : Class()
840 : {
841 0 : return &sClass;
842 : }
843 :
844 : static JSObject*
845 147 : InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
846 : {
847 : return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
848 147 : sProperties, sFunctions, NULL, NULL);
849 : }
850 :
851 : static JSObject*
852 0 : Create(JSContext* aCx, JSObject* aParent, JSString* aType,
853 : bool aLengthComputable, double aLoaded, double aTotal)
854 : {
855 0 : JSString* type = JS_InternJSString(aCx, aType);
856 0 : if (!type) {
857 0 : return NULL;
858 : }
859 :
860 0 : JSObject* obj = JS_NewObject(aCx, &sClass, NULL, aParent);
861 0 : if (!obj) {
862 0 : return NULL;
863 : }
864 :
865 0 : ProgressEvent* priv = new ProgressEvent();
866 0 : SetJSPrivateSafeish(obj, priv);
867 : InitProgressEventCommon(obj, priv, type, false, false, aLengthComputable,
868 0 : aLoaded, aTotal, true);
869 0 : return obj;
870 : }
871 :
872 : protected:
873 0 : ProgressEvent()
874 0 : {
875 0 : MOZ_COUNT_CTOR(mozilla::dom::workers::ProgressEvent);
876 0 : }
877 :
878 0 : ~ProgressEvent()
879 0 : {
880 0 : MOZ_COUNT_DTOR(mozilla::dom::workers::ProgressEvent);
881 0 : }
882 :
883 : enum SLOT {
884 : SLOT_lengthComputable = Event::SLOT_COUNT,
885 : SLOT_loaded,
886 : SLOT_total,
887 :
888 : SLOT_COUNT,
889 : SLOT_FIRST = SLOT_lengthComputable
890 : };
891 :
892 : private:
893 : static ProgressEvent*
894 0 : GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
895 : {
896 0 : JSClass* classPtr = JS_GetClass(aObj);
897 0 : if (classPtr == &sClass) {
898 0 : return GetJSPrivateSafeish<ProgressEvent>(aObj);
899 : }
900 :
901 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
902 : JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
903 0 : classPtr->name);
904 0 : return NULL;
905 : }
906 :
907 : static void
908 0 : InitProgressEventCommon(JSObject* aObj, Event* aEvent, JSString* aType,
909 : JSBool aBubbles, JSBool aCancelable,
910 : JSBool aLengthComputable, double aLoaded,
911 : double aTotal, bool aIsTrusted)
912 : {
913 : Event::InitEventCommon(aObj, aEvent, aType, aBubbles, aCancelable,
914 0 : aIsTrusted);
915 : JS_SetReservedSlot(aObj, SLOT_lengthComputable,
916 0 : aLengthComputable ? JSVAL_TRUE : JSVAL_FALSE);
917 0 : JS_SetReservedSlot(aObj, SLOT_loaded, DOUBLE_TO_JSVAL(aLoaded));
918 0 : JS_SetReservedSlot(aObj, SLOT_total, DOUBLE_TO_JSVAL(aTotal));
919 0 : }
920 :
921 : static JSBool
922 0 : Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
923 : {
924 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
925 0 : sClass.name);
926 0 : return false;
927 : }
928 :
929 : static void
930 147 : Finalize(JSContext* aCx, JSObject* aObj)
931 : {
932 147 : JS_ASSERT(JS_GetClass(aObj) == &sClass);
933 147 : delete GetJSPrivateSafeish<ProgressEvent>(aObj);
934 147 : }
935 :
936 : static JSBool
937 0 : GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
938 : {
939 0 : JS_ASSERT(JSID_IS_INT(aIdval));
940 :
941 0 : int32 slot = JSID_TO_INT(aIdval);
942 :
943 0 : JS_ASSERT(slot >= SLOT_lengthComputable && slot < SLOT_COUNT);
944 :
945 0 : const char*& name = sProperties[slot - SLOT_FIRST].name;
946 0 : ProgressEvent* event = GetInstancePrivate(aCx, aObj, name);
947 0 : if (!event) {
948 0 : return false;
949 : }
950 :
951 0 : *aVp = JS_GetReservedSlot(aObj, slot);
952 0 : return true;
953 : }
954 :
955 : static JSBool
956 0 : InitProgressEvent(JSContext* aCx, unsigned aArgc, jsval* aVp)
957 : {
958 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
959 0 : if (!obj) {
960 0 : return false;
961 : }
962 :
963 0 : ProgressEvent* event = GetInstancePrivate(aCx, obj, sFunctions[0].name);
964 0 : if (!event) {
965 0 : return false;
966 : }
967 :
968 : JSString* type;
969 : JSBool bubbles, cancelable, lengthComputable;
970 : double loaded, total;
971 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "Sbbbdd", &type,
972 : &bubbles, &cancelable, &lengthComputable, &loaded,
973 0 : &total)) {
974 0 : return false;
975 : }
976 :
977 : InitProgressEventCommon(obj, event, type, bubbles, cancelable,
978 0 : lengthComputable, loaded, total, false);
979 0 : return true;
980 : }
981 : };
982 :
983 : JSClass ProgressEvent::sClass = {
984 : "ProgressEvent",
985 : JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
986 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
987 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
988 : JSCLASS_NO_OPTIONAL_MEMBERS
989 : };
990 :
991 : JSPropertySpec ProgressEvent::sProperties[] = {
992 : { "lengthComputable", SLOT_lengthComputable, PROPERTY_FLAGS, GetProperty,
993 : js_GetterOnlyPropertyStub },
994 : { "loaded", SLOT_loaded, PROPERTY_FLAGS, GetProperty,
995 : js_GetterOnlyPropertyStub },
996 : { "total", SLOT_total, PROPERTY_FLAGS, GetProperty,
997 : js_GetterOnlyPropertyStub },
998 : { 0, 0, 0, NULL, NULL }
999 : };
1000 :
1001 : JSFunctionSpec ProgressEvent::sFunctions[] = {
1002 : JS_FN("initProgressEvent", InitProgressEvent, 6, FUNCTION_FLAGS),
1003 : JS_FS_END
1004 : };
1005 :
1006 : Event*
1007 0 : Event::GetPrivate(JSObject* aObj)
1008 : {
1009 0 : if (aObj) {
1010 0 : JSClass* classPtr = JS_GetClass(aObj);
1011 0 : if (IsThisClass(classPtr) ||
1012 0 : MessageEvent::IsThisClass(classPtr) ||
1013 0 : ErrorEvent::IsThisClass(classPtr) ||
1014 0 : classPtr == ProgressEvent::Class()) {
1015 0 : return GetJSPrivateSafeish<Event>(aObj);
1016 : }
1017 : }
1018 0 : return NULL;
1019 : }
1020 :
1021 : } /* anonymous namespace */
1022 :
1023 : BEGIN_WORKERS_NAMESPACE
1024 :
1025 : namespace events {
1026 :
1027 : bool
1028 147 : InitClasses(JSContext* aCx, JSObject* aGlobal, bool aMainRuntime)
1029 : {
1030 147 : JSObject* eventProto = Event::InitClass(aCx, aGlobal, aMainRuntime);
1031 147 : if (!eventProto) {
1032 0 : return false;
1033 : }
1034 :
1035 147 : return MessageEvent::InitClass(aCx, aGlobal, eventProto, aMainRuntime) &&
1036 147 : ErrorEvent::InitClass(aCx, aGlobal, eventProto, aMainRuntime) &&
1037 294 : ProgressEvent::InitClass(aCx, aGlobal, eventProto);
1038 : }
1039 :
1040 : JSObject*
1041 0 : CreateGenericEvent(JSContext* aCx, JSString* aType, bool aBubbles,
1042 : bool aCancelable, bool aMainRuntime)
1043 : {
1044 0 : JSObject* global = JS_GetGlobalForScopeChain(aCx);
1045 0 : return Event::Create(aCx, global, aType, aBubbles, aCancelable, aMainRuntime);
1046 : }
1047 :
1048 : JSObject*
1049 0 : CreateMessageEvent(JSContext* aCx, JSAutoStructuredCloneBuffer& aData,
1050 : nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
1051 : bool aMainRuntime)
1052 : {
1053 0 : JSObject* global = JS_GetGlobalForScopeChain(aCx);
1054 0 : return MessageEvent::Create(aCx, global, aData, aClonedObjects, aMainRuntime);
1055 : }
1056 :
1057 : JSObject*
1058 0 : CreateErrorEvent(JSContext* aCx, JSString* aMessage, JSString* aFilename,
1059 : uint32 aLineNumber, bool aMainRuntime)
1060 : {
1061 0 : JSObject* global = JS_GetGlobalForScopeChain(aCx);
1062 : return ErrorEvent::Create(aCx, global, aMessage, aFilename, aLineNumber,
1063 0 : aMainRuntime);
1064 : }
1065 :
1066 : JSObject*
1067 0 : CreateProgressEvent(JSContext* aCx, JSString* aType, bool aLengthComputable,
1068 : double aLoaded, double aTotal)
1069 : {
1070 0 : JSObject* global = JS_GetGlobalForScopeChain(aCx);
1071 : return ProgressEvent::Create(aCx, global, aType, aLengthComputable, aLoaded,
1072 0 : aTotal);
1073 : }
1074 :
1075 : bool
1076 0 : IsSupportedEventClass(JSObject* aEvent)
1077 : {
1078 0 : return Event::IsSupportedClass(aEvent);
1079 : }
1080 :
1081 : void
1082 0 : SetEventTarget(JSObject* aEvent, JSObject* aTarget)
1083 : {
1084 0 : Event::SetTarget(aEvent, aTarget);
1085 0 : }
1086 :
1087 : bool
1088 0 : EventWasCanceled(JSObject* aEvent)
1089 : {
1090 0 : return Event::WasCanceled(aEvent);
1091 : }
1092 :
1093 : bool
1094 0 : EventImmediatePropagationStopped(JSObject* aEvent)
1095 : {
1096 0 : return Event::ImmediatePropagationStopped(aEvent);
1097 : }
1098 :
1099 : bool
1100 0 : DispatchEventToTarget(JSContext* aCx, JSObject* aTarget, JSObject* aEvent,
1101 : bool* aPreventDefaultCalled)
1102 : {
1103 : static const char kFunctionName[] = "dispatchEvent";
1104 : JSBool hasProperty;
1105 0 : if (!JS_HasProperty(aCx, aTarget, kFunctionName, &hasProperty)) {
1106 0 : return false;
1107 : }
1108 :
1109 0 : JSBool preventDefaultCalled = false;
1110 0 : if (hasProperty) {
1111 0 : jsval argv[] = { OBJECT_TO_JSVAL(aEvent) };
1112 0 : jsval rval = JSVAL_VOID;
1113 0 : if (!JS_CallFunctionName(aCx, aTarget, kFunctionName, ArrayLength(argv),
1114 0 : argv, &rval) ||
1115 0 : !JS_ValueToBoolean(aCx, rval, &preventDefaultCalled)) {
1116 0 : return false;
1117 : }
1118 : }
1119 :
1120 0 : *aPreventDefaultCalled = !!preventDefaultCalled;
1121 0 : return true;
1122 : }
1123 :
1124 : } // namespace events
1125 :
1126 : END_WORKERS_NAMESPACE
|