Bug 699925 - support event.stopImmediatePropagation in workers, r=bent
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sat, 05 Nov 2011 23:41:16 +0200
changeset 79827 7e28b68cf25d0741579acad918d4592088ed3b52
parent 79826 ae228e329b421e35e2b5b8e70586af6fa8c1fb29
child 79842 ec2498505d2372f8a6bf1a1e68422197365fb20a
push id21429
push useropettay@mozilla.com
push dateSat, 05 Nov 2011 21:47:27 +0000
treeherdermozilla-central@7e28b68cf25d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs699925
milestone10.0a1
first release with
nightly linux32
7e28b68cf25d / 10.0a1 / 20111106031055 / files
nightly linux64
7e28b68cf25d / 10.0a1 / 20111106031055 / files
nightly mac
7e28b68cf25d / 10.0a1 / 20111106031055 / files
nightly win32
7e28b68cf25d / 10.0a1 / 20111106031055 / files
nightly win64
7e28b68cf25d / 10.0a1 / 20111106031055 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 699925 - support event.stopImmediatePropagation in workers, r=bent
dom/workers/Events.cpp
dom/workers/Events.h
dom/workers/ListenerManager.cpp
dom/workers/test/eventDispatch_worker.js
--- a/dom/workers/Events.cpp
+++ b/dom/workers/Events.cpp
@@ -70,16 +70,17 @@ class Event : public PrivatizableBase
   static JSClass sMainRuntimeClass;
 
   static JSPropertySpec sProperties[];
   static JSFunctionSpec sFunctions[];
   static JSPropertySpec sStaticProperties[];
 
 protected:
   bool mStopPropagationCalled;
+  bool mStopImmediatePropagationCalled;
 
 public:
   static bool
   IsThisClass(JSClass* aClass)
   {
     return aClass == &sClass || aClass == &sMainRuntimeClass;
   }
 
@@ -163,19 +164,26 @@ public:
     jsval canceled;
     if (!GetPropertyCommon(aCx, aEvent, SLOT_defaultPrevented, &canceled)) {
       return false;
     }
 
     return JSVAL_TO_BOOLEAN(canceled);
   }
 
+  static bool
+  ImmediatePropagationStopped(JSContext* aCx, JSObject* aEvent)
+  {
+    Event* event = GetPrivate(aCx, aEvent);
+    return event ? event->mStopImmediatePropagationCalled : false;
+  }
+
 protected:
   Event()
-  : mStopPropagationCalled(false)
+  : mStopPropagationCalled(false), mStopImmediatePropagationCalled(false)
   {
     MOZ_COUNT_CTOR(mozilla::dom::workers::Event);
   }
 
   virtual ~Event()
   {
     MOZ_COUNT_DTOR(mozilla::dom::workers::Event);
   }
@@ -225,16 +233,17 @@ protected:
   }
 
   static JSBool
   InitEventCommon(JSContext* aCx, JSObject* aObj, Event* aEvent,
                   JSString* aType, JSBool aBubbles, JSBool aCancelable,
                   bool aIsTrusted)
   {
     aEvent->mStopPropagationCalled = false;
+    aEvent->mStopImmediatePropagationCalled = false;
 
     jsval now;
     if (!JS_NewNumberValue(aCx, JS_Now(), &now)) {
       return false;
     }
 
     if (!JS_SetReservedSlot(aCx, aObj, SLOT_type, STRING_TO_JSVAL(aType)) ||
         !JS_SetReservedSlot(aCx, aObj, SLOT_target, JSVAL_NULL) ||
@@ -315,16 +324,31 @@ private:
     }
 
     event->mStopPropagationCalled = true;
 
     return true;
   }
 
   static JSBool
+  StopImmediatePropagation(JSContext* aCx, uintN aArgc, jsval* aVp)
+  {
+    JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
+
+    Event* event = GetInstancePrivate(aCx, obj, sFunctions[3].name);
+    if (!event) {
+      return false;
+    }
+
+    event->mStopImmediatePropagationCalled = true;
+
+    return true;
+  }
+  
+  static JSBool
   PreventDefault(JSContext* aCx, uintN aArgc, jsval* aVp)
   {
     JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
 
     Event* event = GetInstancePrivate(aCx, obj, sFunctions[1].name);
     if (!event) {
       return false;
     }
@@ -394,16 +418,17 @@ JSPropertySpec Event::sProperties[] = {
     js_GetterOnlyPropertyStub },
   { 0, 0, 0, NULL, NULL }
 };
 
 JSFunctionSpec Event::sFunctions[] = {
   JS_FN("stopPropagation", StopPropagation, 0, FUNCTION_FLAGS),
   JS_FN("preventDefault", PreventDefault, 0, FUNCTION_FLAGS),
   JS_FN("initEvent", InitEvent, 3, FUNCTION_FLAGS),
+  JS_FN("stopImmediatePropagation", StopImmediatePropagation, 0, FUNCTION_FLAGS),
   JS_FS_END
 };
 
 JSPropertySpec Event::sStaticProperties[] = {
   { "CAPTURING_PHASE", CAPTURING_PHASE, CONSTANT_FLAGS, GetConstant, NULL },
   { "AT_TARGET", AT_TARGET, CONSTANT_FLAGS, GetConstant, NULL },
   { "BUBBLING_PHASE", BUBBLING_PHASE, CONSTANT_FLAGS, GetConstant, NULL },
   { 0, 0, 0, NULL, NULL }
@@ -1111,16 +1136,22 @@ SetEventTarget(JSContext* aCx, JSObject*
 
 bool
 EventWasCanceled(JSContext* aCx, JSObject* aEvent)
 {
   return Event::WasCanceled(aCx, aEvent);
 }
 
 bool
+EventImmediatePropagationStopped(JSContext* aCx, JSObject* aEvent)
+{
+  return Event::ImmediatePropagationStopped(aCx, aEvent);
+}
+
+bool
 DispatchEventToTarget(JSContext* aCx, JSObject* aTarget, JSObject* aEvent,
                       bool* aPreventDefaultCalled)
 {
   static const char kFunctionName[] = "dispatchEvent";
   JSBool hasProperty;
   if (!JS_HasProperty(aCx, aTarget, kFunctionName, &hasProperty)) {
     return false;
   }
--- a/dom/workers/Events.h
+++ b/dom/workers/Events.h
@@ -76,16 +76,19 @@ IsSupportedEventClass(JSContext* aCx, JS
 
 bool
 SetEventTarget(JSContext* aCx, JSObject* aEvent, JSObject* aTarget);
 
 bool
 EventWasCanceled(JSContext* aCx, JSObject* aEvent);
 
 bool
+EventImmediatePropagationStopped(JSContext* aCx, JSObject* aEvent);
+
+bool
 DispatchEventToTarget(JSContext* aCx, JSObject* aTarget, JSObject* aEvent,
                       bool* aPreventDefaultCalled);
 
 } // namespace events
 
 END_WORKERS_NAMESPACE
 
 #endif /* mozilla_dom_workers_events_h__ */
--- a/dom/workers/ListenerManager.cpp
+++ b/dom/workers/ListenerManager.cpp
@@ -387,16 +387,20 @@ ListenerManager::DispatchEvent(JSContext
     return true;
   }
 
   if (!events::SetEventTarget(aCx, aEvent, aTarget)) {
     return false;
   }
 
   for (size_t index = 0; index < listeners.length(); index++) {
+    if (events::EventImmediatePropagationStopped(aCx, aEvent)) {
+      break;
+    }
+
     // If anything fails in here we want to report the exception and continue on
     // to the next listener rather than bailing out. If something fails and
     // does not set an exception then we bail out entirely as we've either run
     // out of memory or the operation callback has indicated that we should
     // stop running.
 
     jsval listenerVal = listeners[index];
 
--- a/dom/workers/test/eventDispatch_worker.js
+++ b/dom/workers/test/eventDispatch_worker.js
@@ -17,19 +17,24 @@ addEventListener(fakeEventType, function
 
 addEventListener(fakeEventType, function(event) {
   if (event.target !== self || event.currentTarget !== self) {
     throw new Error("Fake event has bad target!");
   }
   if (event.isTrusted) {
     throw new Error("Event should be untrusted!");
   }
+  event.stopImmediatePropagation();
   postMessage(event.data);
 }, false, true);
 
+addEventListener(fakeEventType, function(event) {
+  throw new Error("This shouldn't get called because of stopImmediatePropagation.");
+}, false, true);
+
 var count = 0;
 onmessage = function(event) {
   if (event.target !== self || event.currentTarget !== self) {
     throw new Error("Event has bad target!");
   }
 
   if (!count++) {
     var exception;