Bug 1362195 - 1. Add EventDispatcher::Dispatch for C++ code; r=snorp
authorJim Chen <nchen@mozilla.com>
Thu, 11 May 2017 16:40:17 -0400
changeset 357984 741e175e254c45b1cbc7f53043ae2f6bf5b9bcb1
parent 357983 cab30987328afd255f2b9bd08b6c420e7fabdaa0
child 357985 2acf5f4b6943de39e799ed0eaa4af8a727d37f14
push id31808
push usercbook@mozilla.com
push dateFri, 12 May 2017 12:37:49 +0000
treeherdermozilla-central@030c0a7c8781 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1362195
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1362195 - 1. Add EventDispatcher::Dispatch for C++ code; r=snorp Add an EventDispatcher::Dispatch function for C++ code, so native code can dispatch events to JS/Java.
widget/android/EventDispatcher.cpp
widget/android/EventDispatcher.h
--- a/widget/android/EventDispatcher.cpp
+++ b/widget/android/EventDispatcher.cpp
@@ -541,17 +541,17 @@ UnboxData(jni::String::Param aEvent, JSC
     jni::Object::LocalRef jniData(jni::GetGeckoThreadEnv(), aData);
     nsresult rv = NS_ERROR_INVALID_ARG;
 
     if (!aBundleOnly) {
         rv = UnboxValue(aCx, jniData, aOut);
     } else if (!jniData || jniData.IsInstanceOf<java::GeckoBundle>()) {
         rv = UnboxBundle(aCx, jniData, aOut);
     }
-    if (rv != NS_ERROR_INVALID_ARG) {
+    if (rv != NS_ERROR_INVALID_ARG || !aEvent) {
         return rv;
     }
 
     nsCString event = aEvent->ToCString();
     if (JS_IsExceptionPending(aCx)) {
         JS_ReportWarningUTF8(aCx, "Error dispatching %s", event.get());
     } else {
         JS_ReportErrorUTF8(aCx, "Invalid event data for %s", event.get());
@@ -714,16 +714,32 @@ EventDispatcher::DispatchOnGecko(Listene
         }
         const nsresult rv = list->listeners[i]->OnEvent(
                 aEvent, aData, aCallback);
         Unused << NS_WARN_IF(NS_FAILED(rv));
     }
     return NS_OK;
 }
 
+java::EventDispatcher::NativeCallbackDelegate::LocalRef
+EventDispatcher::WrapCallback(nsIAndroidEventCallback* aCallback)
+{
+    java::EventDispatcher::NativeCallbackDelegate::LocalRef
+            callback(jni::GetGeckoThreadEnv());
+
+    if (aCallback) {
+        callback = java::EventDispatcher::NativeCallbackDelegate::New();
+        NativeCallbackDelegateSupport::AttachNative(
+                callback,
+                MakeUnique<NativeCallbackDelegateSupport>(
+                        aCallback, mDOMWindow));
+    }
+    return callback;
+}
+
 NS_IMETHODIMP
 EventDispatcher::Dispatch(JS::HandleValue aEvent, JS::HandleValue aData,
                           nsIAndroidEventCallback* aCallback, JSContext* aCx)
 {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!aEvent.isString()) {
         NS_WARNING("Invalid event name");
@@ -746,28 +762,42 @@ EventDispatcher::Dispatch(JS::HandleValu
         return NS_OK;
     }
 
     jni::Object::LocalRef data(jni::GetGeckoThreadEnv());
     nsresult rv = BoxData(event, aCx, aData, data, /* ObjectOnly */ true);
     NS_ENSURE_SUCCESS(rv, JS_IsExceptionPending(aCx) ? NS_OK : rv);
 
     dom::AutoNoJSAPI nojsapi;
+    mDispatcher->DispatchToThreads(event, data, WrapCallback(aCallback));
+    return NS_OK;
+}
 
-    java::EventDispatcher::NativeCallbackDelegate::LocalRef
-            callback(data.Env());
-    if (aCallback) {
-        callback = java::EventDispatcher::NativeCallbackDelegate::New();
-        NativeCallbackDelegateSupport::AttachNative(
-                callback,
-                MakeUnique<NativeCallbackDelegateSupport>(
-                        aCallback, mDOMWindow));
+nsresult
+EventDispatcher::Dispatch(const char16_t* aEvent,
+                          java::GeckoBundle::Param aData,
+                          nsIAndroidEventCallback* aCallback)
+{
+    nsDependentString event(aEvent);
+
+    ListenersList* list = mListenersMap.Get(event);
+    if (list) {
+        dom::AutoJSAPI jsapi;
+        JS::RootedValue data(jsapi.cx());
+        nsresult rv = UnboxData(/* Event */ nullptr, jsapi.cx(), aData, &data,
+                                /* BundleOnly */ true);
+        NS_ENSURE_SUCCESS(rv, rv);
+        return DispatchOnGecko(list, event, data, aCallback);
     }
 
-    mDispatcher->DispatchToThreads(event, data, callback);
+    if (!mDispatcher) {
+        return NS_OK;
+    }
+
+    mDispatcher->DispatchToThreads(event, aData, WrapCallback(aCallback));
     return NS_OK;
 }
 
 nsresult
 EventDispatcher::IterateEvents(JSContext* aCx, JS::HandleValue aEvents,
                                IterateEventsCallback aCallback,
                                nsIAndroidEventListener* aListener)
 {
--- a/widget/android/EventDispatcher.h
+++ b/widget/android/EventDispatcher.h
@@ -36,16 +36,20 @@ public:
     NS_DECL_NSIANDROIDEVENTDISPATCHER
 
     EventDispatcher() {}
 
     void Attach(java::EventDispatcher::Param aDispatcher,
                 nsPIDOMWindowOuter* aDOMWindow);
     void Detach();
 
+    nsresult Dispatch(const char16_t* aEvent,
+                      java::GeckoBundle::Param aData = nullptr,
+                      nsIAndroidEventCallback* aCallback = nullptr);
+
     using NativesBase::DisposeNative;
 
     bool HasGeckoListener(jni::String::Param aEvent);
     void DispatchToGecko(jni::String::Param aEvent,
                          jni::Object::Param aData,
                          jni::Object::Param aCallback);
 
     static nsresult UnboxBundle(JSContext* aCx,
@@ -78,14 +82,17 @@ private:
                            IterateEventsCallback aCallback,
                            nsIAndroidEventListener* aListener);
     nsresult RegisterEventLocked(const nsAString&, nsIAndroidEventListener*);
     nsresult UnregisterEventLocked(const nsAString&, nsIAndroidEventListener*);
 
     nsresult DispatchOnGecko(ListenersList* list, const nsAString& aEvent,
                              JS::HandleValue aData,
                              nsIAndroidEventCallback* aCallback);
+
+    java::EventDispatcher::NativeCallbackDelegate::LocalRef
+    WrapCallback(nsIAndroidEventCallback* aCallback);
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif // mozilla_widget_EventDispatcher_h