From de18629ca00209a4d009b6af21ce0959ec38d7c8 Mon Sep 17 00:00:00 2001 From: JP Dinger Date: Fri, 29 Jan 2010 16:30:26 +0100 Subject: [PATCH] mozilla plugin: rework events listeners to dom level 2 type, sort of. --- projects/mozilla/control/npolibvlc.cpp | 225 +++++-------------------- projects/mozilla/control/npolibvlc.h | 24 +-- projects/mozilla/vlcplugin.cpp | 186 ++++++++++++++------ projects/mozilla/vlcplugin.h | 135 ++++++--------- 4 files changed, 234 insertions(+), 336 deletions(-) diff --git a/projects/mozilla/control/npolibvlc.cpp b/projects/mozilla/control/npolibvlc.cpp index 976d7733e5..2efe11688c 100644 --- a/projects/mozilla/control/npolibvlc.cpp +++ b/projects/mozilla/control/npolibvlc.cpp @@ -76,45 +76,6 @@ NPVariant copyNPVariant(const NPVariant& original) return res; } -// Parse an event Array given as a NPObject by JS. -// This function is similar to LibvlcPlaylistNPObject::parseOptions, -// but we don't use it because it's not clearly accessible and the FIXME flags -// implie that it might be modified. -bool parseEventArray(NPObject *obj, eventtypes_bitmap_t &eventToGet, NPP instance) -{ - NPIdentifier propId = NPN_GetStringIdentifier("length"); - NPVariant value; - - if (!NPN_GetProperty(instance, obj, propId, &value)) - return false; - - int count = NPVARIANT_TO_INT32(value); - NPN_ReleaseVariantValue(&value); - if (count == 0) - return false; - - int nOptions = 0; - while (nOptions < count) - { - propId = NPN_GetIntIdentifier(nOptions); - // if there is no other string in the array. - if( ! NPN_GetProperty(instance, obj, propId, &value) ) - break; - - // if the element is not a string. - if( ! NPVARIANT_IS_STRING(value) ) - { - NPN_ReleaseVariantValue(&value); - break; - } - - if (!eventToGet.add_event(NPVARIANT_TO_STRING(value).utf8characters)) - return false; - nOptions++; - } - return true; -} - /* ** implementation of libvlc root object */ @@ -134,6 +95,7 @@ LibvlcRootNPObject::~LibvlcRootNPObject() if( audioObj ) NPN_ReleaseObject(audioObj); if( inputObj ) NPN_ReleaseObject(inputObj); if( playlistObj ) NPN_ReleaseObject(playlistObj); + if( subtitleObj ) NPN_ReleaseObject(subtitleObj); if( videoObj ) NPN_ReleaseObject(videoObj); } } @@ -145,7 +107,6 @@ const NPUTF8 * const LibvlcRootNPObject::propertyNames[] = "playlist", "subtitle", "video", - "events", "VersionInfo", }; COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames); @@ -157,7 +118,6 @@ enum LibvlcRootNPObjectPropertyIds ID_root_playlist, ID_root_subtitle, ID_root_video, - ID_root_events, ID_root_VersionInfo, }; @@ -189,14 +149,6 @@ LibvlcRootNPObject::getProperty(int index, NPVariant &result) InstantObj( videoObj ); OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result); return INVOKERESULT_NO_ERROR; - case ID_root_events: - // create child object in lazyman fashion to avoid - // ownership problem with firefox - if( ! eventObj ) - eventObj = NPN_CreateObject(_instance, - RuntimeNPClass::getClass()); - OBJECT_TO_NPVARIANT(NPN_RetainObject(eventObj), result); - return INVOKERESULT_NO_ERROR; case ID_root_VersionInfo: return invokeResultString(libvlc_get_version(),result); default: @@ -209,34 +161,65 @@ LibvlcRootNPObject::getProperty(int index, NPVariant &result) const NPUTF8 * const LibvlcRootNPObject::methodNames[] = { "versionInfo", + "addEventListener", + "removeEventListener", }; COUNTNAMES(LibvlcRootNPObject,methodCount,methodNames); enum LibvlcRootNPObjectMethodIds { ID_root_versionInfo, + ID_root_addeventlistener, + ID_root_removeeventlistener, }; RuntimeNPObject::InvokeResult LibvlcRootNPObject::invoke(int index, const NPVariant *args, uint32_t argCount, NPVariant &result) { /* is plugin still running */ - if( isPluginRunning() ) + if( !isPluginRunning() ) + return INVOKERESULT_GENERIC_ERROR; + + libvlc_exception_t ex; + libvlc_exception_init(&ex); + + switch( index ) { - libvlc_exception_t ex; - libvlc_exception_init(&ex); + case ID_root_versionInfo: + if( 0 != argCount ) + return INVOKERESULT_NO_SUCH_METHOD; + return invokeResultString(libvlc_get_version(),result); + + case ID_root_addeventlistener: + case ID_root_removeeventlistener: + if( (3 != argCount) || + !NPVARIANT_IS_STRING(args[0]) || + !NPVARIANT_IS_OBJECT(args[1]) || + !NPVARIANT_IS_BOOLEAN(args[2]) ) + break; - switch( index ) + if( !VlcPlugin::canUseEventListener() ) { - case ID_root_versionInfo: - if( 0 != argCount ) - return INVOKERESULT_NO_SUCH_METHOD; - return invokeResultString(libvlc_get_version(),result); - default: - ; + NPN_SetException(this, ERROR_API_VERSION); + return INVOKERESULT_GENERIC_ERROR; } + + NPObject *listener = NPVARIANT_TO_OBJECT(args[1]); + VlcPlugin* p_plugin = getPrivate(); + + bool b; + if(ID_root_removeeventlistener!=index) + b = p_plugin->events.insert(NPVARIANT_TO_STRING(args[0]), + listener, NPVARIANT_TO_BOOLEAN(args[2])); + else + b = p_plugin->events.remove(NPVARIANT_TO_STRING(args[0]), + listener, NPVARIANT_TO_BOOLEAN(args[2])); + + VOID_TO_NPVARIANT(result); + + return b ? INVOKERESULT_NO_ERROR : INVOKERESULT_GENERIC_ERROR; } - return INVOKERESULT_GENERIC_ERROR; + return INVOKERESULT_NO_SUCH_METHOD; } /* @@ -2061,125 +2044,3 @@ LibvlcDeinterlaceNPObject::invoke(int index, const NPVariant *args, return INVOKERESULT_NO_ERROR; } - - -/* -** implementation of libvlc event object -*/ - -const NPUTF8 * const LibvlcEventNPObject::propertyNames[] = -{ -}; - -enum LibvlcEventNPObjectPropertyIds -{ -}; -COUNTNAMES(LibvlcEventNPObject,propertyCount,propertyNames); - -const NPUTF8 * const LibvlcEventNPObject::methodNames[] = -{ - "addListener", - "removeListeners", -}; -COUNTNAMES(LibvlcEventNPObject,methodCount,methodNames); - -enum LibvlcEventNPObjectMethodIds -{ - ID_event_addListener, - ID_event_removeListeners, -}; - -bool LibvlcEventNPObject::parseArgs(const NPVariant *args, uint32_t argCount, - eventtypes_bitmap_t &eventToGet) -{ - if (argCount > 2) - eventToGet.clear(); - - for (int argIndex = 2; argIndex < argCount; argIndex++) - { - if (NPVARIANT_IS_STRING(args[argIndex])) - { - if (!eventToGet.add_event(NPVARIANT_TO_STRING(args[argIndex]).utf8characters)) - return false; - } - else if (NPVARIANT_IS_OBJECT(args[argIndex])) - { - if (!parseEventArray(NPVARIANT_TO_OBJECT(args[argIndex]), eventToGet, _instance)) - return false; - } - else - return false; - } - return true; -} - -RuntimeNPObject::InvokeResult -LibvlcEventNPObject::invoke(int index, const NPVariant *args, - uint32_t argCount, NPVariant &result) -{ - /* is plugin still running */ - if( isPluginRunning() ) - { - libvlc_exception_t ex; - libvlc_exception_init(&ex); - - switch( index ) - { - case ID_event_addListener: - if (argCount >= 2) - { - // Checks if the first argument is a NPObject - if (!NPVARIANT_IS_OBJECT(args[0])) - return INVOKERESULT_NO_SUCH_METHOD; - - // Checks if the browser has the NPAPI version 0.19 at least. - if (!VlcPlugin::canUseEventListener()) - { - NPN_SetException(this, strdup(ERROR_API_VERSION)); - return INVOKERESULT_GENERIC_ERROR; - } - - VlcPlugin* p_plugin = getPrivate(); - - // Gets the binary field corresponding to the events the - // listener must listen to if specified. - // Else, listen to all events. - eventtypes_bitmap_t eventToGet; - eventToGet.set_all_events(); - - if (!parseArgs(args, argCount, eventToGet)) - { - NPN_SetException(this, strdup(ERROR_EVENT_NOT_FOUND)); - return INVOKERESULT_GENERIC_ERROR; - } - - NPObject *listener = NPVARIANT_TO_OBJECT(args[0]); - NPN_RetainObject(listener); - - EventListener *eventListener = new EventListener(); - eventListener->listener = listener; - eventListener->id = copyNPVariant(args[1]); - eventListener->eventMap = eventToGet; - - p_plugin->eventToCatch.add_event(eventToGet); - - p_plugin->eventListeners.push_back(eventListener); - - return INVOKERESULT_NO_ERROR; - } - return INVOKERESULT_NO_SUCH_METHOD; - case ID_event_removeListeners: - if (argCount == 0) - { - VlcPlugin* p_plugin = getPrivate(); - p_plugin->eventListeners.clear(); - p_plugin->eventToCatch.clear(); - return INVOKERESULT_NO_ERROR; - } - return INVOKERESULT_NO_SUCH_METHOD; - default: - ; - } - } - return INVOKERESULT_GENERIC_ERROR; -} diff --git a/projects/mozilla/control/npolibvlc.h b/projects/mozilla/control/npolibvlc.h index 25e1adce69..c6d8694b6d 100644 --- a/projects/mozilla/control/npolibvlc.h +++ b/projects/mozilla/control/npolibvlc.h @@ -38,8 +38,7 @@ protected: inputObj(NULL), playlistObj(NULL), subtitleObj(NULL), - videoObj(NULL), - eventObj(NULL) {}; + videoObj(NULL) { } virtual ~LibvlcRootNPObject(); @@ -59,7 +58,6 @@ private: NPObject *playlistObj; NPObject *subtitleObj; NPObject *videoObj; - NPObject *eventObj; }; class LibvlcAudioNPObject: public RuntimeNPObject @@ -265,23 +263,3 @@ protected: InvokeResult invoke(int index, const NPVariant *args, uint32_t argCount, NPVariant &result); }; -class LibvlcEventNPObject: public RuntimeNPObject -{ -protected: - friend class RuntimeNPClass; - - LibvlcEventNPObject(NPP instance, const NPClass *aClass) : - RuntimeNPObject(instance, aClass) {}; - virtual ~LibvlcEventNPObject() {}; - - static const int propertyCount; - static const NPUTF8 * const propertyNames[]; - - static const int methodCount; - static const NPUTF8 * const methodNames[]; - - InvokeResult invoke(int index, const NPVariant *args, uint32_t argCount, NPVariant &result); - - bool parseArgs(const NPVariant *args, uint32_t argCount, - eventtypes_bitmap_t &eventToGet); -}; diff --git a/projects/mozilla/vlcplugin.cpp b/projects/mozilla/vlcplugin.cpp index aa5010135c..0028b32be5 100644 --- a/projects/mozilla/vlcplugin.cpp +++ b/projects/mozilla/vlcplugin.cpp @@ -36,7 +36,7 @@ #include "control/npolibvlc.h" #include -#include +#include /***************************************************************************** * VlcPlugin constructor and destructor @@ -87,48 +87,156 @@ static bool boolValue(const char *value) { !strcasecmp(value, "yes") ); } -void eventAsync(void *param) + +void EventObj::deliver(NPP browser) { - VlcPlugin *plugin = (VlcPlugin*)param; NPVariant result; - NPVariant params[2]; + NPVariant params[1]; - pthread_mutex_lock(&plugin->mutex); + pthread_mutex_lock(&mutex); - for (int i = 0; i < plugin->eventList.size(); i++) + for( ev_l::iterator i=_elist.begin();i!=_elist.end();++i ) { - for (int j = 0; j < plugin->eventListeners.size(); j++) - { - libvlc_event_type_t event = plugin->eventList[i]; + libvlc_event_type_t event = *i; + STRINGZ_TO_NPVARIANT(libvlc_event_type_name(event), params[0]); + + // Invalid events aren't supposed to be queued up. + // if( !have_event(event) ) continue; - if (plugin->eventListeners[j]->eventMap.have_event(event)) + for( lr_l::iterator j=_llist.begin();j!=_llist.end();++j ) + { + if (j->get(event)) { - STRINGZ_TO_NPVARIANT(libvlc_event_type_name(event), params[0]); - params[1] = plugin->eventListeners[j]->id; - NPN_InvokeDefault(plugin->getBrowser(), plugin->eventListeners[j]->listener, params, 2, &result); + NPN_InvokeDefault(browser, j->listener(), params, 1, &result); NPN_ReleaseVariantValue(&result); } } } - plugin->eventList.clear(); + _elist.clear(); - pthread_mutex_unlock(&plugin->mutex); + pthread_mutex_unlock(&mutex); } -void event_callback(const libvlc_event_t* event, void *param) +void VlcPlugin::eventAsync(void *param) { VlcPlugin *plugin = (VlcPlugin*)param; + plugin->events.deliver(plugin->getBrowser()); +} - pthread_mutex_lock(&plugin->mutex); +void EventObj::callback(const libvlc_event_t* event) +{ + pthread_mutex_lock(&mutex); - if (plugin->eventToCatch.have_event(event->type)) - plugin->eventList.push_back(event->type); + if( have_event(event->type) ) + _elist.push_back(event->type); - pthread_mutex_unlock(&plugin->mutex); + pthread_mutex_unlock(&mutex); +} +void VlcPlugin::event_callback(const libvlc_event_t* event, void *param) +{ + VlcPlugin *plugin = (VlcPlugin*)param; + plugin->events.callback(event); +#ifdef XP_UNIX NPN_PluginThreadAsyncCall(plugin->getBrowser(), eventAsync, plugin); +#else + NPN_SetException(this, "NPN_PluginThreadAsyncCall not implemented yet."); +#endif +} + +inline EventObj::event_t EventObj::find_event(const char *s) const +{ + event_t i; + for(i=0;i=maxbit() ) + return false; + + if( !have_event(e) && !ask_for_event(e) ) + return false; + + lr_l::iterator i; + for(i=_llist.begin();i!=_llist.end();++i) + if(i->listener()==l && i->bubble()==b) + break; + + if( i == _llist.end() ) { + _llist.push_back(Listener(e,l,b)); + } else { + if( i->get(e) ) + return false; + i->get(e); + } +} + + +bool EventObj::remove(const NPString &s, NPObject *l, bool b) +{ + event_t e = find_event(s.utf8characters); + if( e>=maxbit() || !get(e) ) + return false; + + bool any=false; + for(lr_l::iterator i=_llist.begin();i!=_llist.end();) + { + if(i->listener()!=l || i->bubble()!=b) + any|=i->get(e); + else + { + i->reset(e); + if(i->empty()) + { + i=_llist.erase(i); + continue; + } + } + ++i; + } + if(!any) + unask_for_event(e); +} + + +void EventObj::hook_manager(libvlc_event_manager_t *em, + libvlc_callback_t cb, void *udata) +{ + _em = em; _cb = cb; _ud = udata; + if( !_em ) + return; + for(size_t i=0;i::getClass(); - if (pthread_mutex_init(&mutex, NULL) != 0) + if( !events.init() ) return NPERR_GENERIC_ERROR; return NPERR_NO_ERROR; @@ -315,20 +423,14 @@ VlcPlugin::~VlcPlugin() free(psz_text); if( libvlc_media_player ) + { + events.unhook_manager(); libvlc_media_player_release( libvlc_media_player ); + } if( libvlc_media_list ) libvlc_media_list_release( libvlc_media_list ); if( libvlc_instance ) libvlc_release(libvlc_instance); - - for (int i = 0; i < eventListeners.size(); i++) - { - NPN_ReleaseObject(eventListeners[i]->listener); - NPN_ReleaseVariantValue(&(eventListeners[i]->id)); - delete eventListeners[i]; - } - - pthread_mutex_destroy(&mutex); } /***************************************************************************** @@ -391,7 +493,6 @@ int VlcPlugin::playlist_add_extended_untrusted( const char *mrl, const char *nam bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex ) { libvlc_media_t *p_m = NULL; - libvlc_event_manager_t *eventManager = NULL; libvlc_media_list_lock(libvlc_media_list); @@ -410,6 +511,7 @@ bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex ) if( libvlc_media_player ) { + events.unhook_manager(); libvlc_media_player_release( libvlc_media_player ); libvlc_media_player = NULL; } @@ -418,25 +520,9 @@ bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex ) if( libvlc_media_player ) { set_player_window(); - - // Registers the events we're interested in. - eventManager = libvlc_media_player_event_manager(libvlc_media_player, ex); - - libvlc_event_attach(eventManager, libvlc_MediaPlayerOpening, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerBuffering, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerPlaying, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerStopped, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerPaused, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerForward, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerBackward, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerEncounteredError, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerTimeChanged, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerPositionChanged, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerTitleChanged, event_callback, this, ex); - libvlc_event_attach(eventManager, libvlc_MediaPlayerSnapshotTaken, event_callback, this, ex); - + events.hook_manager( + libvlc_media_player_event_manager(libvlc_media_player), + event_callback, this); } libvlc_media_release( p_m ); diff --git a/projects/mozilla/vlcplugin.h b/projects/mozilla/vlcplugin.h index 7cc0519641..950df74d1a 100644 --- a/projects/mozilla/vlcplugin.h +++ b/projects/mozilla/vlcplugin.h @@ -30,8 +30,10 @@ #define __VLCPLUGIN_H__ #include +#include #include #include + #include "control/nporuntime.h" #if !defined(XP_MACOSX) && !defined(XP_UNIX) && !defined(XP_WIN) @@ -90,11 +92,7 @@ private: enum { bmax=M, bpu=1<>shift]&(1<<(idx&mask)); - } - + bool get(size_t idx) const { return bits[idx>>shift]&(1<<(idx&mask)); } void set(size_t idx) { bits[idx>>shift]|= 1<<(idx&mask); } void reset(size_t idx) { bits[idx>>shift]&=~(1<<(idx&mask)); } void toggle(size_t idx) { bits[idx>>shift]^= 1<<(idx&mask); } @@ -102,86 +100,63 @@ public: void clear() { memset(bits,0,sizeof(bits)); } bitmap() { clear(); } ~bitmap() { } + bool empty() const { // naive invert() will break this + for(size_t i=0;i parent; +typedef bitmap eventtypes_bitmap_t; -class eventtypes_bitmap_t: private bitmap { + +class EventObj: private eventtypes_bitmap_t +{ private: typedef libvlc_event_type_t event_t; - event_t find_event(const char *s) const - { - event_t i; - for(i=0;i lr_l; + typedef std::vector ev_l; + lr_l _llist; + ev_l _elist; + pthread_mutex_t mutex; -// Structure used to represent an EventListener. -// It contains the listener object that will be invoked, -// An Id given by the addEventListener function and sent -// when invoking the listener. Can be anything or nothing. -// The profile associated with the listener used to invoke -// the listener only to some events. -typedef struct s_EventListener -{ - NPObject *listener; - NPVariant id; - eventtypes_bitmap_t eventMap; - -} EventListener; + bool ask_for_event(event_t e); + void unask_for_event(event_t e); +}; -void event_callback(const libvlc_event_t* event, void *param); class VlcPlugin { @@ -302,14 +277,9 @@ public: bool player_has_vout( libvlc_exception_t * ); - // Events related members - std::vector eventListeners; // List of registered listerners. - std::vector eventList; // List of event sent by VLC that must be returned to JS. - eventtypes_bitmap_t eventToCatch; - pthread_mutex_t mutex; - static bool canUseEventListener(); + EventObj events; private: bool playlist_select(int,libvlc_exception_t *); void set_player_window(); @@ -346,6 +316,9 @@ private: int i_last_position; #endif + + static void eventAsync(void *); + static void event_callback(const libvlc_event_t *, void *); }; /******************************************************************************* -- 2.39.2