]> git.sesse.net Git - vlc/blob - projects/mozilla/control/npolibvlc.cpp
mozilla: factorize.
[vlc] / projects / mozilla / control / npolibvlc.cpp
1 /*****************************************************************************
2  * npolibvlc.cpp: official Javascript APIs
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  * Copyright (C) 2010 M2X BV
6  *
7  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
8  *          JP Dinger <jpd@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #include "config.h"
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 /* Mozilla stuff */
32 #ifdef HAVE_MOZILLA_CONFIG_H
33 #   include <mozilla-config.h>
34 #endif
35
36 #include "vlcplugin.h"
37 #include "npolibvlc.h"
38
39 #include "position.h"
40
41 /*
42 ** Local helper macros and function
43 */
44 #define COUNTNAMES(a,b,c) const int a::b = sizeof(a::c)/sizeof(NPUTF8 *)
45 #define RETURN_ON_EXCEPTION(this,ex) \
46     do { if( libvlc_exception_raised(&ex) ) \
47     { \
48         NPN_SetException(this, libvlc_errmsg()); \
49         libvlc_exception_clear(&ex); \
50         return INVOKERESULT_GENERIC_ERROR; \
51     } } while(false)
52
53 #define ERROR_EVENT_NOT_FOUND "ERROR: One or more events could not be found."
54 #define ERROR_API_VERSION "ERROR: NPAPI version not high enough. (Gecko >= 1.9 needed)"
55
56 // Make a copy of an NPVariant.
57 NPVariant copyNPVariant(const NPVariant& original)
58 {
59     NPVariant res;
60
61     if (NPVARIANT_IS_STRING(original))
62         STRINGZ_TO_NPVARIANT(strdup(NPVARIANT_TO_STRING(original).utf8characters), res);
63     else if (NPVARIANT_IS_INT32(original))
64         INT32_TO_NPVARIANT(NPVARIANT_TO_INT32(original), res);
65     else if (NPVARIANT_IS_DOUBLE(original))
66         DOUBLE_TO_NPVARIANT(NPVARIANT_TO_DOUBLE(original), res);
67     else if (NPVARIANT_IS_OBJECT(original))
68     {
69         NPObject *obj = NPVARIANT_TO_OBJECT(original);
70         NPN_RetainObject(obj);
71         OBJECT_TO_NPVARIANT(obj, res);
72     }
73     else if (NPVARIANT_IS_BOOLEAN(original))
74         BOOLEAN_TO_NPVARIANT(NPVARIANT_TO_BOOLEAN(original), res);
75
76     return res;
77 }
78
79 /*
80 ** implementation of libvlc root object
81 */
82
83 LibvlcRootNPObject::~LibvlcRootNPObject()
84 {
85     /*
86     ** When the plugin is destroyed, firefox takes it upon itself to
87     ** destroy all 'live' script objects and ignores refcounting.
88     ** Therefore we cannot safely assume that refcounting will control
89     ** lifespan of objects. Hence they are only lazily created on
90     ** request, so that firefox can take ownership, and are not released
91     ** when the plugin is destroyed.
92     */
93     if( isValid() )
94     {
95         if( audioObj    ) NPN_ReleaseObject(audioObj);
96         if( inputObj    ) NPN_ReleaseObject(inputObj);
97         if( playlistObj ) NPN_ReleaseObject(playlistObj);
98         if( subtitleObj ) NPN_ReleaseObject(subtitleObj);
99         if( videoObj    ) NPN_ReleaseObject(videoObj);
100     }
101 }
102
103 const NPUTF8 * const LibvlcRootNPObject::propertyNames[] =
104 {
105     "audio",
106     "input",
107     "playlist",
108     "subtitle",
109     "video",
110     "VersionInfo",
111 };
112 COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames);
113
114 enum LibvlcRootNPObjectPropertyIds
115 {
116     ID_root_audio = 0,
117     ID_root_input,
118     ID_root_playlist,
119     ID_root_subtitle,
120     ID_root_video,
121     ID_root_VersionInfo,
122 };
123
124 RuntimeNPObject::InvokeResult
125 LibvlcRootNPObject::getProperty(int index, NPVariant &result)
126 {
127     /* is plugin still running */
128     if( isPluginRunning() )
129     {
130         switch( index )
131         {
132             case ID_root_audio:
133                 InstantObj<LibvlcAudioNPObject>( audioObj );
134                 OBJECT_TO_NPVARIANT(NPN_RetainObject(audioObj), result);
135                 return INVOKERESULT_NO_ERROR;
136             case ID_root_input:
137                 InstantObj<LibvlcInputNPObject>( inputObj );
138                 OBJECT_TO_NPVARIANT(NPN_RetainObject(inputObj), result);
139                 return INVOKERESULT_NO_ERROR;
140             case ID_root_playlist:
141                 InstantObj<LibvlcPlaylistNPObject>( playlistObj );
142                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistObj), result);
143                 return INVOKERESULT_NO_ERROR;
144             case ID_root_subtitle:
145                 InstantObj<LibvlcSubtitleNPObject>( subtitleObj );
146                 OBJECT_TO_NPVARIANT(NPN_RetainObject(subtitleObj), result);
147                 return INVOKERESULT_NO_ERROR;
148             case ID_root_video:
149                 InstantObj<LibvlcVideoNPObject>( videoObj );
150                 OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);
151                 return INVOKERESULT_NO_ERROR;
152             case ID_root_VersionInfo:
153                 return invokeResultString(libvlc_get_version(),result);
154             default:
155                 ;
156         }
157     }
158     return INVOKERESULT_GENERIC_ERROR;
159 }
160
161 const NPUTF8 * const LibvlcRootNPObject::methodNames[] =
162 {
163     "versionInfo",
164     "addEventListener",
165     "removeEventListener",
166 };
167 COUNTNAMES(LibvlcRootNPObject,methodCount,methodNames);
168
169 enum LibvlcRootNPObjectMethodIds
170 {
171     ID_root_versionInfo,
172     ID_root_addeventlistener,
173     ID_root_removeeventlistener,
174 };
175
176 RuntimeNPObject::InvokeResult LibvlcRootNPObject::invoke(int index,
177                   const NPVariant *args, uint32_t argCount, NPVariant &result)
178 {
179     /* is plugin still running */
180     if( !isPluginRunning() )
181         return INVOKERESULT_GENERIC_ERROR;
182
183     libvlc_exception_t ex;
184     libvlc_exception_init(&ex);
185
186     switch( index )
187     {
188     case ID_root_versionInfo:
189         if( 0 != argCount )
190             return INVOKERESULT_NO_SUCH_METHOD;
191         return invokeResultString(libvlc_get_version(),result);
192
193     case ID_root_addeventlistener:
194     case ID_root_removeeventlistener:
195         if( (3 != argCount) ||
196             !NPVARIANT_IS_STRING(args[0]) ||
197             !NPVARIANT_IS_OBJECT(args[1]) ||
198             !NPVARIANT_IS_BOOLEAN(args[2]) )
199             break;
200
201         if( !VlcPlugin::canUseEventListener() )
202         {
203             NPN_SetException(this, ERROR_API_VERSION);
204             return INVOKERESULT_GENERIC_ERROR;
205         }
206
207         NPObject *listener = NPVARIANT_TO_OBJECT(args[1]);
208         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
209
210         bool b;
211         if(ID_root_removeeventlistener!=index)
212             b = p_plugin->events.insert(NPVARIANT_TO_STRING(args[0]),
213                                      listener, NPVARIANT_TO_BOOLEAN(args[2]));
214         else
215             b = p_plugin->events.remove(NPVARIANT_TO_STRING(args[0]),
216                                      listener, NPVARIANT_TO_BOOLEAN(args[2]));
217
218         VOID_TO_NPVARIANT(result);
219
220         return b ? INVOKERESULT_NO_ERROR : INVOKERESULT_GENERIC_ERROR;
221     }
222     return INVOKERESULT_NO_SUCH_METHOD;
223 }
224
225 /*
226 ** implementation of libvlc audio object
227 */
228
229 const NPUTF8 * const LibvlcAudioNPObject::propertyNames[] =
230 {
231     "mute",
232     "volume",
233     "track",
234     "count",
235     "channel",
236 };
237 COUNTNAMES(LibvlcAudioNPObject,propertyCount,propertyNames);
238
239 enum LibvlcAudioNPObjectPropertyIds
240 {
241     ID_audio_mute,
242     ID_audio_volume,
243     ID_audio_track,
244     ID_audio_count,
245     ID_audio_channel,
246 };
247
248 RuntimeNPObject::InvokeResult
249 LibvlcAudioNPObject::getProperty(int index, NPVariant &result)
250 {
251     /* is plugin still running */
252     if( isPluginRunning() )
253     {
254         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
255         libvlc_exception_t ex;
256         libvlc_exception_init(&ex);
257
258         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
259         RETURN_ON_EXCEPTION(this,ex);
260
261         switch( index )
262         {
263             case ID_audio_mute:
264             {
265                 bool muted = libvlc_audio_get_mute(p_md);
266                 BOOLEAN_TO_NPVARIANT(muted, result);
267                 return INVOKERESULT_NO_ERROR;
268             }
269             case ID_audio_volume:
270             {
271                 int volume = libvlc_audio_get_volume(p_md);
272                 INT32_TO_NPVARIANT(volume, result);
273                 return INVOKERESULT_NO_ERROR;
274             }
275             case ID_audio_track:
276             {
277                 int track = libvlc_audio_get_track(p_md);
278                 INT32_TO_NPVARIANT(track, result);
279                 return INVOKERESULT_NO_ERROR;
280             }
281             case ID_audio_count:
282             {
283                 // get the number of audio track available
284                 int i_track = libvlc_audio_get_track_count(p_md);
285                 // return it
286                 INT32_TO_NPVARIANT(i_track, result);
287                 return INVOKERESULT_NO_ERROR;
288             }
289             case ID_audio_channel:
290             {
291                 int channel = libvlc_audio_get_channel(p_md);
292                 INT32_TO_NPVARIANT(channel, result);
293                 return INVOKERESULT_NO_ERROR;
294             }
295             default:
296                 ;
297         }
298     }
299     return INVOKERESULT_GENERIC_ERROR;
300 }
301
302 RuntimeNPObject::InvokeResult
303 LibvlcAudioNPObject::setProperty(int index, const NPVariant &value)
304 {
305     /* is plugin still running */
306     if( isPluginRunning() )
307     {
308         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
309         libvlc_exception_t ex;
310         libvlc_exception_init(&ex);
311
312         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
313         RETURN_ON_EXCEPTION(this,ex);
314
315         switch( index )
316         {
317             case ID_audio_mute:
318                 if( NPVARIANT_IS_BOOLEAN(value) )
319                 {
320                     libvlc_audio_set_mute(p_md,
321                                           NPVARIANT_TO_BOOLEAN(value));
322                     return INVOKERESULT_NO_ERROR;
323                 }
324                 return INVOKERESULT_INVALID_VALUE;
325             case ID_audio_volume:
326                 if( isNumberValue(value) )
327                 {
328                     libvlc_audio_set_volume(p_md, numberValue(value));
329                     return INVOKERESULT_NO_ERROR;
330                 }
331                 return INVOKERESULT_INVALID_VALUE;
332             case ID_audio_track:
333                 if( isNumberValue(value) )
334                 {
335                     libvlc_audio_set_track(p_md, numberValue(value));
336                     return INVOKERESULT_NO_ERROR;
337                 }
338                 return INVOKERESULT_INVALID_VALUE;
339             case ID_audio_channel:
340                 if( isNumberValue(value) )
341                 {
342                     libvlc_audio_set_channel(p_md, numberValue(value));
343                     return INVOKERESULT_NO_ERROR;
344                 }
345                 return INVOKERESULT_INVALID_VALUE;
346             default:
347                 ;
348         }
349     }
350     return INVOKERESULT_GENERIC_ERROR;
351 }
352
353 const NPUTF8 * const LibvlcAudioNPObject::methodNames[] =
354 {
355     "toggleMute",
356     "description",
357 };
358 COUNTNAMES(LibvlcAudioNPObject,methodCount,methodNames);
359
360 enum LibvlcAudioNPObjectMethodIds
361 {
362     ID_audio_togglemute,
363     ID_audio_description,
364 };
365
366 RuntimeNPObject::InvokeResult
367 LibvlcAudioNPObject::invoke(int index, const NPVariant *args,
368                             uint32_t argCount, NPVariant &result)
369 {
370     /* is plugin still running */
371     if( isPluginRunning() )
372     {
373         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
374         libvlc_exception_t ex;
375         libvlc_exception_init(&ex);
376
377         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
378         RETURN_ON_EXCEPTION(this,ex);
379
380         switch( index )
381         {
382             case ID_audio_togglemute:
383                 if( argCount == 0 )
384                 {
385                     libvlc_audio_toggle_mute(p_md);
386                     VOID_TO_NPVARIANT(result);
387                     return INVOKERESULT_NO_ERROR;
388                 }
389                 return INVOKERESULT_NO_SUCH_METHOD;
390             case ID_audio_description:
391             {
392                 if( argCount == 1)
393                 {
394                     char *psz_name;
395                     int i_trackID, i_limit, i;
396                     libvlc_track_description_t *p_trackDesc;
397
398                     /* get tracks description */
399                     p_trackDesc = libvlc_audio_get_track_description(p_md);
400                     if( !p_trackDesc )
401                         return INVOKERESULT_GENERIC_ERROR;
402
403                     /* get the number of track available */
404                     i_limit = libvlc_audio_get_track_count(p_md);
405
406                     /* check if a number is given by the user
407                      * and get the track number */
408                     if( isNumberValue(args[0]) )
409                         i_trackID = numberValue(args[0]);
410                     else
411                         return INVOKERESULT_INVALID_VALUE;
412
413                     /* if bad number is given return invalid value */
414                     if ( ( i_trackID > ( i_limit - 1 ) ) || ( i_trackID < 0 ) )
415                         return INVOKERESULT_INVALID_VALUE;
416
417                     /* get the good trackDesc */
418                     for( i = 0 ; i < i_trackID ; i++ )
419                     {
420                         p_trackDesc = p_trackDesc->p_next;
421                     }
422                     psz_name = p_trackDesc->psz_name;
423
424                     /* display the name of the track chosen */
425                     return invokeResultString( psz_name, result );
426                 }
427                 return INVOKERESULT_NO_SUCH_METHOD;
428             }
429             default:
430                 ;
431         }
432     }
433     return INVOKERESULT_GENERIC_ERROR;
434 }
435
436 /*
437 ** implementation of libvlc input object
438 */
439
440 const NPUTF8 * const LibvlcInputNPObject::propertyNames[] =
441 {
442     "length",
443     "position",
444     "time",
445     "state",
446     "rate",
447     "fps",
448     "hasVout",
449 };
450 COUNTNAMES(LibvlcInputNPObject,propertyCount,propertyNames);
451
452 enum LibvlcInputNPObjectPropertyIds
453 {
454     ID_input_length,
455     ID_input_position,
456     ID_input_time,
457     ID_input_state,
458     ID_input_rate,
459     ID_input_fps,
460     ID_input_hasvout,
461 };
462
463 RuntimeNPObject::InvokeResult
464 LibvlcInputNPObject::getProperty(int index, NPVariant &result)
465 {
466     /* is plugin still running */
467     if( isPluginRunning() )
468     {
469         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
470         libvlc_exception_t ex;
471         libvlc_exception_init(&ex);
472
473         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
474         if( libvlc_exception_raised(&ex) )
475         {
476             if( index != ID_input_state )
477             {
478                 NPN_SetException(this, libvlc_errmsg());
479                 libvlc_exception_clear(&ex);
480                 return INVOKERESULT_GENERIC_ERROR;
481             }
482             else
483             {
484                 /* for input state, return CLOSED rather than an exception */
485                 INT32_TO_NPVARIANT(0, result);
486                 libvlc_exception_clear(&ex);
487                 return INVOKERESULT_NO_ERROR;
488             }
489         }
490
491         switch( index )
492         {
493             case ID_input_length:
494             {
495                 double val = (double)libvlc_media_player_get_length(p_md);
496                 DOUBLE_TO_NPVARIANT(val, result);
497                 return INVOKERESULT_NO_ERROR;
498             }
499             case ID_input_position:
500             {
501                 double val = libvlc_media_player_get_position(p_md);
502                 DOUBLE_TO_NPVARIANT(val, result);
503                 return INVOKERESULT_NO_ERROR;
504             }
505             case ID_input_time:
506             {
507                 double val = (double)libvlc_media_player_get_time(p_md);
508                 DOUBLE_TO_NPVARIANT(val, result);
509                 return INVOKERESULT_NO_ERROR;
510             }
511             case ID_input_state:
512             {
513                 int val = libvlc_media_player_get_state(p_md);
514                 RETURN_ON_EXCEPTION(this,ex);
515                 INT32_TO_NPVARIANT(val, result);
516                 return INVOKERESULT_NO_ERROR;
517             }
518             case ID_input_rate:
519             {
520                 float val = libvlc_media_player_get_rate(p_md);
521                 DOUBLE_TO_NPVARIANT(val, result);
522                 return INVOKERESULT_NO_ERROR;
523             }
524             case ID_input_fps:
525             {
526                 double val = libvlc_media_player_get_fps(p_md);
527                 DOUBLE_TO_NPVARIANT(val, result);
528                 return INVOKERESULT_NO_ERROR;
529             }
530             case ID_input_hasvout:
531             {
532                 bool val = p_plugin->player_has_vout(&ex);
533                 RETURN_ON_EXCEPTION(this,ex);
534                 BOOLEAN_TO_NPVARIANT(val, result);
535                 return INVOKERESULT_NO_ERROR;
536             }
537             default:
538                 ;
539         }
540     }
541     return INVOKERESULT_GENERIC_ERROR;
542 }
543
544 RuntimeNPObject::InvokeResult
545 LibvlcInputNPObject::setProperty(int index, const NPVariant &value)
546 {
547     /* is plugin still running */
548     if( isPluginRunning() )
549     {
550         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
551         libvlc_exception_t ex;
552         libvlc_exception_init(&ex);
553
554         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
555         RETURN_ON_EXCEPTION(this,ex);
556
557         switch( index )
558         {
559             case ID_input_position:
560             {
561                 if( ! NPVARIANT_IS_DOUBLE(value) )
562                 {
563                     return INVOKERESULT_INVALID_VALUE;
564                 }
565
566                 float val = (float)NPVARIANT_TO_DOUBLE(value);
567                 libvlc_media_player_set_position(p_md, val);
568                 return INVOKERESULT_NO_ERROR;
569             }
570             case ID_input_time:
571             {
572                 int64_t val;
573                 if( NPVARIANT_IS_INT32(value) )
574                     val = (int64_t)NPVARIANT_TO_INT32(value);
575                 else if( NPVARIANT_IS_DOUBLE(value) )
576                     val = (int64_t)NPVARIANT_TO_DOUBLE(value);
577                 else
578                 {
579                     return INVOKERESULT_INVALID_VALUE;
580                 }
581
582                 libvlc_media_player_set_time(p_md, val);
583                 return INVOKERESULT_NO_ERROR;
584             }
585             case ID_input_rate:
586             {
587                 float val;
588                 if( NPVARIANT_IS_INT32(value) )
589                     val = (float)NPVARIANT_TO_INT32(value);
590                 else if( NPVARIANT_IS_DOUBLE(value) )
591                     val = (float)NPVARIANT_TO_DOUBLE(value);
592                 else
593                 {
594                     return INVOKERESULT_INVALID_VALUE;
595                 }
596
597                 libvlc_media_player_set_rate(p_md, val);
598                 return INVOKERESULT_NO_ERROR;
599             }
600             default:
601                 ;
602         }
603     }
604     return INVOKERESULT_GENERIC_ERROR;
605 }
606
607 const NPUTF8 * const LibvlcInputNPObject::methodNames[] =
608 {
609     /* no methods */
610     "none",
611 };
612 COUNTNAMES(LibvlcInputNPObject,methodCount,methodNames);
613
614 enum LibvlcInputNPObjectMethodIds
615 {
616     ID_none,
617 };
618
619 RuntimeNPObject::InvokeResult
620 LibvlcInputNPObject::invoke(int index, const NPVariant *args,
621                                     uint32_t argCount, NPVariant &result)
622 {
623     /* is plugin still running */
624     if( isPluginRunning() )
625     {
626         switch( index )
627         {
628             case ID_none:
629                 return INVOKERESULT_NO_SUCH_METHOD;
630             default:
631                 ;
632         }
633     }
634     return INVOKERESULT_GENERIC_ERROR;
635 }
636
637 /*
638 ** implementation of libvlc playlist items object
639 */
640
641 const NPUTF8 * const LibvlcPlaylistItemsNPObject::propertyNames[] =
642 {
643     "count",
644 };
645 COUNTNAMES(LibvlcPlaylistItemsNPObject,propertyCount,propertyNames);
646
647 enum LibvlcPlaylistItemsNPObjectPropertyIds
648 {
649     ID_playlistitems_count,
650 };
651
652 RuntimeNPObject::InvokeResult
653 LibvlcPlaylistItemsNPObject::getProperty(int index, NPVariant &result)
654 {
655     /* is plugin still running */
656     if( isPluginRunning() )
657     {
658         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
659
660         switch( index )
661         {
662             case ID_playlistitems_count:
663             {
664                 int val = p_plugin->playlist_count();
665                 INT32_TO_NPVARIANT(val, result);
666                 return INVOKERESULT_NO_ERROR;
667             }
668             default:
669                 ;
670         }
671     }
672     return INVOKERESULT_GENERIC_ERROR;
673 }
674
675 const NPUTF8 * const LibvlcPlaylistItemsNPObject::methodNames[] =
676 {
677     "clear",
678     "remove",
679 };
680 COUNTNAMES(LibvlcPlaylistItemsNPObject,methodCount,methodNames);
681
682 enum LibvlcPlaylistItemsNPObjectMethodIds
683 {
684     ID_playlistitems_clear,
685     ID_playlistitems_remove,
686 };
687
688 RuntimeNPObject::InvokeResult
689 LibvlcPlaylistItemsNPObject::invoke(int index, const NPVariant *args,
690                                     uint32_t argCount, NPVariant &result)
691 {
692     /* is plugin still running */
693     if( isPluginRunning() )
694     {
695         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
696         libvlc_exception_t ex;
697         libvlc_exception_init(&ex);
698
699         switch( index )
700         {
701             case ID_playlistitems_clear:
702                 if( argCount == 0 )
703                 {
704                     p_plugin->playlist_clear(&ex);
705                     RETURN_ON_EXCEPTION(this,ex);
706                     VOID_TO_NPVARIANT(result);
707                     return INVOKERESULT_NO_ERROR;
708                 }
709                 return INVOKERESULT_NO_SUCH_METHOD;
710             case ID_playlistitems_remove:
711                 if( (argCount == 1) && isNumberValue(args[0]) )
712                 {
713                     p_plugin->playlist_delete_item(numberValue(args[0]),&ex);
714                     RETURN_ON_EXCEPTION(this,ex);
715                     VOID_TO_NPVARIANT(result);
716                     return INVOKERESULT_NO_ERROR;
717                 }
718                 return INVOKERESULT_NO_SUCH_METHOD;
719             default:
720                 ;
721         }
722     }
723     return INVOKERESULT_GENERIC_ERROR;
724 }
725
726 /*
727 ** implementation of libvlc playlist object
728 */
729
730 LibvlcPlaylistNPObject::~LibvlcPlaylistNPObject()
731 {
732     // Why the isValid()?
733     if( isValid() && playlistItemsObj )
734         NPN_ReleaseObject(playlistItemsObj);
735 };
736
737 const NPUTF8 * const LibvlcPlaylistNPObject::propertyNames[] =
738 {
739     "itemCount", /* deprecated */
740     "isPlaying",
741     "items",
742 };
743 COUNTNAMES(LibvlcPlaylistNPObject,propertyCount,propertyNames);
744
745 enum LibvlcPlaylistNPObjectPropertyIds
746 {
747     ID_playlist_itemcount,
748     ID_playlist_isplaying,
749     ID_playlist_items,
750 };
751
752 RuntimeNPObject::InvokeResult
753 LibvlcPlaylistNPObject::getProperty(int index, NPVariant &result)
754 {
755     /* is plugin still running */
756     if( isPluginRunning() )
757     {
758         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
759
760         switch( index )
761         {
762             case ID_playlist_itemcount: /* deprecated */
763             {
764                 int val = p_plugin->playlist_count();
765                 INT32_TO_NPVARIANT(val, result);
766                 return INVOKERESULT_NO_ERROR;
767             }
768             case ID_playlist_isplaying:
769             {
770                 int val = p_plugin->playlist_isplaying();
771                 BOOLEAN_TO_NPVARIANT(val, result);
772                 return INVOKERESULT_NO_ERROR;
773             }
774             case ID_playlist_items:
775             {
776                 InstantObj<LibvlcPlaylistItemsNPObject>( playlistItemsObj );
777                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistItemsObj), result);
778                 return INVOKERESULT_NO_ERROR;
779             }
780             default:
781                 ;
782         }
783     }
784     return INVOKERESULT_GENERIC_ERROR;
785 }
786
787 const NPUTF8 * const LibvlcPlaylistNPObject::methodNames[] =
788 {
789     "add",
790     "play",
791     "playItem",
792     "togglePause",
793     "stop",
794     "next",
795     "prev",
796     "clear", /* deprecated */
797     "removeItem", /* deprecated */
798 };
799 COUNTNAMES(LibvlcPlaylistNPObject,methodCount,methodNames);
800
801 enum LibvlcPlaylistNPObjectMethodIds
802 {
803     ID_playlist_add,
804     ID_playlist_play,
805     ID_playlist_playItem,
806     ID_playlist_togglepause,
807     ID_playlist_stop,
808     ID_playlist_next,
809     ID_playlist_prev,
810     ID_playlist_clear,
811     ID_playlist_removeitem
812 };
813
814 RuntimeNPObject::InvokeResult
815 LibvlcPlaylistNPObject::invoke(int index, const NPVariant *args,
816                                uint32_t argCount, NPVariant &result)
817 {
818     /* is plugin still running */
819     if( isPluginRunning() )
820     {
821         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
822         libvlc_exception_t ex;
823         libvlc_exception_init(&ex);
824
825         switch( index )
826         {
827             // XXX FIXME this needs squashing into something much smaller
828             case ID_playlist_add:
829             {
830                 if( (argCount < 1) || (argCount > 3) )
831                     return INVOKERESULT_NO_SUCH_METHOD;
832                 if( !NPVARIANT_IS_STRING(args[0]) )
833                     return INVOKERESULT_NO_SUCH_METHOD;
834
835                 // grab URL
836                 if( NPVARIANT_IS_NULL(args[0]) )
837                     return INVOKERESULT_NO_SUCH_METHOD;
838
839                 char *s = stringValue(NPVARIANT_TO_STRING(args[0]));
840                 if( !s )
841                     return INVOKERESULT_OUT_OF_MEMORY;
842
843                 char *url = p_plugin->getAbsoluteURL(s);
844                 if( url )
845                     free(s);
846                 else
847                     // problem with combining url, use argument
848                     url = s;
849
850                 char *name = NULL;
851
852                 // grab name if available
853                 if( argCount > 1 )
854                 {
855                     if( NPVARIANT_IS_NULL(args[1]) )
856                     {
857                         // do nothing
858                     }
859                     else if( NPVARIANT_IS_STRING(args[1]) )
860                     {
861                         name = stringValue(NPVARIANT_TO_STRING(args[1]));
862                     }
863                     else
864                     {
865                         free(url);
866                         return INVOKERESULT_INVALID_VALUE;
867                     }
868                 }
869
870                 int i_options = 0;
871                 char** ppsz_options = NULL;
872
873                 // grab options if available
874                 if( argCount > 2 )
875                 {
876                     if( NPVARIANT_IS_NULL(args[2]) )
877                     {
878                         // do nothing
879                     }
880                     else if( NPVARIANT_IS_STRING(args[2]) )
881                     {
882                         parseOptions(NPVARIANT_TO_STRING(args[2]),
883                                      &i_options, &ppsz_options);
884
885                     }
886                     else if( NPVARIANT_IS_OBJECT(args[2]) )
887                     {
888                         parseOptions(NPVARIANT_TO_OBJECT(args[2]),
889                                      &i_options, &ppsz_options);
890                     }
891                     else
892                     {
893                         free(url);
894                         free(name);
895                         return INVOKERESULT_INVALID_VALUE;
896                     }
897                 }
898
899                 int item = p_plugin->playlist_add_extended_untrusted(url, name,
900                       i_options, const_cast<const char **>(ppsz_options), &ex);
901                 free(url);
902                 free(name);
903                 for( int i=0; i< i_options; ++i )
904                 {
905                     free(ppsz_options[i]);
906                 }
907                 free(ppsz_options);
908
909                 RETURN_ON_EXCEPTION(this,ex);
910                 INT32_TO_NPVARIANT(item, result);
911                 return INVOKERESULT_NO_ERROR;
912             }
913             case ID_playlist_play:
914                 if( argCount == 0 )
915                 {
916                     p_plugin->playlist_play(&ex);
917                     RETURN_ON_EXCEPTION(this,ex);
918                     VOID_TO_NPVARIANT(result);
919                     return INVOKERESULT_NO_ERROR;
920                 }
921                 return INVOKERESULT_NO_SUCH_METHOD;
922             case ID_playlist_playItem:
923                 if( (argCount == 1) && isNumberValue(args[0]) )
924                 {
925                     p_plugin->playlist_play_item(numberValue(args[0]),&ex);
926                     RETURN_ON_EXCEPTION(this,ex);
927                     VOID_TO_NPVARIANT(result);
928                     return INVOKERESULT_NO_ERROR;
929                 }
930                 return INVOKERESULT_NO_SUCH_METHOD;
931             case ID_playlist_togglepause:
932                 if( argCount == 0 )
933                 {
934                     p_plugin->playlist_pause();
935                     VOID_TO_NPVARIANT(result);
936                     return INVOKERESULT_NO_ERROR;
937                 }
938                 return INVOKERESULT_NO_SUCH_METHOD;
939             case ID_playlist_stop:
940                 if( argCount == 0 )
941                 {
942                     p_plugin->playlist_stop();
943                     VOID_TO_NPVARIANT(result);
944                     return INVOKERESULT_NO_ERROR;
945                 }
946                 return INVOKERESULT_NO_SUCH_METHOD;
947             case ID_playlist_next:
948                 if( argCount == 0 )
949                 {
950                     p_plugin->playlist_next(&ex);
951                     RETURN_ON_EXCEPTION(this,ex);
952                     VOID_TO_NPVARIANT(result);
953                     return INVOKERESULT_NO_ERROR;
954                 }
955                 return INVOKERESULT_NO_SUCH_METHOD;
956             case ID_playlist_prev:
957                 if( argCount == 0 )
958                 {
959                     p_plugin->playlist_prev(&ex);
960                     RETURN_ON_EXCEPTION(this,ex);
961                     VOID_TO_NPVARIANT(result);
962                     return INVOKERESULT_NO_ERROR;
963                 }
964                 return INVOKERESULT_NO_SUCH_METHOD;
965             case ID_playlist_clear: /* deprecated */
966                 if( argCount == 0 )
967                 {
968                     p_plugin->playlist_clear(&ex);
969                     RETURN_ON_EXCEPTION(this,ex);
970                     VOID_TO_NPVARIANT(result);
971                     return INVOKERESULT_NO_ERROR;
972                 }
973                 return INVOKERESULT_NO_SUCH_METHOD;
974             case ID_playlist_removeitem: /* deprecated */
975                 if( (argCount == 1) && isNumberValue(args[0]) )
976                 {
977                     p_plugin->playlist_delete_item(numberValue(args[0]), &ex);
978                     RETURN_ON_EXCEPTION(this,ex);
979                     VOID_TO_NPVARIANT(result);
980                     return INVOKERESULT_NO_ERROR;
981                 }
982                 return INVOKERESULT_NO_SUCH_METHOD;
983             default:
984                 ;
985         }
986     }
987     return INVOKERESULT_GENERIC_ERROR;
988 }
989
990 // XXX FIXME The new playlist_add creates a media instance and feeds it
991 // XXX FIXME these options one at a time, so this hunk of code does lots
992 // XXX FIXME of unnecessairy work. Break out something that can do one
993 // XXX FIXME option at a time and doesn't need to realloc().
994 // XXX FIXME Same for the other version of parseOptions.
995
996 void LibvlcPlaylistNPObject::parseOptions(const NPString &nps,
997                                          int *i_options, char*** ppsz_options)
998 {
999     if( nps.utf8length )
1000     {
1001         char *s = stringValue(nps);
1002         char *val = s;
1003         if( val )
1004         {
1005             long capacity = 16;
1006             char **options = (char **)malloc(capacity*sizeof(char *));
1007             if( options )
1008             {
1009                 int nOptions = 0;
1010
1011                 char *end = val + nps.utf8length;
1012                 while( val < end )
1013                 {
1014                     // skip leading blanks
1015                     while( (val < end)
1016                         && ((*val == ' ' ) || (*val == '\t')) )
1017                         ++val;
1018
1019                     char *start = val;
1020                     // skip till we get a blank character
1021                     while( (val < end)
1022                         && (*val != ' ' )
1023                         && (*val != '\t') )
1024                     {
1025                         char c = *(val++);
1026                         if( ('\'' == c) || ('"' == c) )
1027                         {
1028                             // skip till end of string
1029                             while( (val < end) && (*(val++) != c ) );
1030                         }
1031                     }
1032
1033                     if( val > start )
1034                     {
1035                         if( nOptions == capacity )
1036                         {
1037                             capacity += 16;
1038                             char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1039                             if( ! moreOptions )
1040                             {
1041                                 /* failed to allocate more memory */
1042                                 free(s);
1043                                 /* return what we got so far */
1044                                 *i_options = nOptions;
1045                                 *ppsz_options = options;
1046                                 return;
1047                             }
1048                             options = moreOptions;
1049                         }
1050                         *(val++) = '\0';
1051                         options[nOptions++] = strdup(start);
1052                     }
1053                     else
1054                         // must be end of string
1055                         break;
1056                 }
1057                 *i_options = nOptions;
1058                 *ppsz_options = options;
1059             }
1060             free(s);
1061         }
1062     }
1063 }
1064
1065 // XXX FIXME See comment at the other parseOptions variant.
1066 void LibvlcPlaylistNPObject::parseOptions(NPObject *obj, int *i_options,
1067                                           char*** ppsz_options)
1068 {
1069     /* WARNING: Safari does not implement NPN_HasProperty/NPN_HasMethod */
1070
1071     NPVariant value;
1072
1073     /* we are expecting to have a Javascript Array object */
1074     NPIdentifier propId = NPN_GetStringIdentifier("length");
1075     if( NPN_GetProperty(_instance, obj, propId, &value) )
1076     {
1077         int count = numberValue(value);
1078         NPN_ReleaseVariantValue(&value);
1079
1080         if( count )
1081         {
1082             long capacity = 16;
1083             char **options = (char **)malloc(capacity*sizeof(char *));
1084             if( options )
1085             {
1086                 int nOptions = 0;
1087
1088                 while( nOptions < count )
1089                 {
1090                     propId = NPN_GetIntIdentifier(nOptions);
1091                     if( ! NPN_GetProperty(_instance, obj, propId, &value) )
1092                         /* return what we got so far */
1093                         break;
1094
1095                     if( ! NPVARIANT_IS_STRING(value) )
1096                     {
1097                         /* return what we got so far */
1098                         NPN_ReleaseVariantValue(&value);
1099                         break;
1100                     }
1101
1102                     if( nOptions == capacity )
1103                     {
1104                         capacity += 16;
1105                         char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1106                         if( ! moreOptions )
1107                         {
1108                             /* failed to allocate more memory */
1109                             NPN_ReleaseVariantValue(&value);
1110                             /* return what we got so far */
1111                             *i_options = nOptions;
1112                             *ppsz_options = options;
1113                             break;
1114                         }
1115                         options = moreOptions;
1116                     }
1117
1118                     options[nOptions++] = stringValue(value);
1119                     NPN_ReleaseVariantValue(&value);
1120                 }
1121                 *i_options = nOptions;
1122                 *ppsz_options = options;
1123             }
1124         }
1125     }
1126 }
1127
1128 /*
1129 ** implementation of libvlc subtitle object
1130 */
1131
1132 const NPUTF8 * const LibvlcSubtitleNPObject::propertyNames[] =
1133 {
1134     "track",
1135     "count",
1136 };
1137
1138 enum LibvlcSubtitleNPObjectPropertyIds
1139 {
1140     ID_subtitle_track,
1141     ID_subtitle_count,
1142 };
1143 COUNTNAMES(LibvlcSubtitleNPObject,propertyCount,propertyNames);
1144
1145 RuntimeNPObject::InvokeResult
1146 LibvlcSubtitleNPObject::getProperty(int index, NPVariant &result)
1147 {
1148     /* is plugin still running */
1149     if( isPluginRunning() )
1150     {
1151         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1152         libvlc_exception_t ex;
1153         libvlc_exception_init(&ex);
1154
1155         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1156         RETURN_ON_EXCEPTION(this,ex);
1157
1158         switch( index )
1159         {
1160             case ID_subtitle_track:
1161             {
1162                 /* get the current subtitle ID */
1163                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1164                 RETURN_ON_EXCEPTION(this,ex);
1165                 /* return it */
1166                 INT32_TO_NPVARIANT(i_spu, result);
1167                 return INVOKERESULT_NO_ERROR;
1168             }
1169             case ID_subtitle_count:
1170             {
1171                 /* get the number of subtitles available */
1172                 int i_spu = libvlc_video_get_spu_count(p_md, &ex);
1173                 RETURN_ON_EXCEPTION(this,ex);
1174                 /* return it */
1175                 INT32_TO_NPVARIANT(i_spu, result);
1176                 return INVOKERESULT_NO_ERROR;
1177             }
1178         }
1179     }
1180     return INVOKERESULT_GENERIC_ERROR;
1181 }
1182
1183 RuntimeNPObject::InvokeResult
1184 LibvlcSubtitleNPObject::setProperty(int index, const NPVariant &value)
1185 {
1186     /* is plugin still running */
1187     if( isPluginRunning() )
1188     {
1189         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1190         libvlc_exception_t ex;
1191         libvlc_exception_init(&ex);
1192
1193         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1194         RETURN_ON_EXCEPTION(this,ex);
1195
1196         switch( index )
1197         {
1198             case ID_subtitle_track:
1199             {
1200                 if( isNumberValue(value) )
1201                 {
1202                     /* set the new subtitle track to show */
1203                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1204                     RETURN_ON_EXCEPTION(this,ex);
1205
1206                     return INVOKERESULT_NO_ERROR;
1207                 }
1208                 return INVOKERESULT_INVALID_VALUE;
1209             }
1210         }
1211     }
1212     return INVOKERESULT_GENERIC_ERROR;
1213 }
1214
1215 const NPUTF8 * const LibvlcSubtitleNPObject::methodNames[] =
1216 {
1217     "description"
1218 };
1219 COUNTNAMES(LibvlcSubtitleNPObject,methodCount,methodNames);
1220
1221 enum LibvlcSubtitleNPObjectMethodIds
1222 {
1223     ID_subtitle_description
1224 };
1225
1226 RuntimeNPObject::InvokeResult
1227 LibvlcSubtitleNPObject::invoke(int index, const NPVariant *args,
1228                             uint32_t argCount, NPVariant &result)
1229 {
1230     /* is plugin still running */
1231     if( isPluginRunning() )
1232     {
1233         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1234         libvlc_exception_t ex;
1235         libvlc_exception_init(&ex);
1236
1237         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1238         RETURN_ON_EXCEPTION(this,ex);
1239
1240         switch( index )
1241         {
1242             case ID_subtitle_description:
1243             {
1244                 if( argCount == 1)
1245                 {
1246                     char *psz_name;
1247                     int i_spuID, i_limit, i;
1248                     libvlc_track_description_t *p_spuDesc;
1249
1250                     /* get subtitles description */
1251                     p_spuDesc = libvlc_video_get_spu_description(p_md);
1252                     if( !p_spuDesc )
1253                         return INVOKERESULT_GENERIC_ERROR;
1254
1255                     /* get the number of subtitle available */
1256                     i_limit = libvlc_video_get_spu_count(p_md, &ex);
1257                     RETURN_ON_EXCEPTION(this,ex);
1258
1259                     /* check if a number is given by the user
1260                      * and get the subtitle number */
1261                     if( isNumberValue(args[0]) )
1262                         i_spuID = numberValue(args[0]);
1263                     else
1264                         return INVOKERESULT_INVALID_VALUE;
1265
1266                     /* if bad number is given return invalid value */
1267                     if ( ( i_spuID > ( i_limit -1 ) ) || ( i_spuID < 0 ) )
1268                         return INVOKERESULT_INVALID_VALUE;
1269
1270                     /* get the good spuDesc */
1271                     for( i = 0 ; i < i_spuID ; i++ )
1272                     {
1273                         p_spuDesc = p_spuDesc->p_next;
1274                     }
1275                     psz_name = p_spuDesc->psz_name;
1276
1277                     /* return the name of the track chosen */
1278                     return invokeResultString(psz_name, result);
1279                 }
1280                 return INVOKERESULT_NO_SUCH_METHOD;
1281             }
1282             default:
1283                 return INVOKERESULT_NO_SUCH_METHOD;
1284         }
1285     }
1286     return INVOKERESULT_GENERIC_ERROR;
1287 }
1288
1289 /*
1290 ** implementation of libvlc video object
1291 */
1292
1293 LibvlcVideoNPObject::~LibvlcVideoNPObject()
1294 {
1295     if( isValid() )
1296     {
1297         if( marqueeObj ) NPN_ReleaseObject(marqueeObj);
1298         if( logoObj    ) NPN_ReleaseObject(logoObj);
1299         if( deintObj   ) NPN_ReleaseObject(deintObj);
1300     }
1301 }
1302
1303 const NPUTF8 * const LibvlcVideoNPObject::propertyNames[] =
1304 {
1305     "fullscreen",
1306     "height",
1307     "width",
1308     "aspectRatio",
1309     "subtitle",
1310     "crop",
1311     "teletext",
1312     "marquee",
1313     "logo",
1314     "deinterlace",
1315 };
1316
1317 enum LibvlcVideoNPObjectPropertyIds
1318 {
1319     ID_video_fullscreen,
1320     ID_video_height,
1321     ID_video_width,
1322     ID_video_aspectratio,
1323     ID_video_subtitle,
1324     ID_video_crop,
1325     ID_video_teletext,
1326     ID_video_marquee,
1327     ID_video_logo,
1328     ID_video_deinterlace,
1329 };
1330 COUNTNAMES(LibvlcVideoNPObject,propertyCount,propertyNames);
1331
1332 RuntimeNPObject::InvokeResult
1333 LibvlcVideoNPObject::getProperty(int index, NPVariant &result)
1334 {
1335     /* is plugin still running */
1336     if( isPluginRunning() )
1337     {
1338         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1339         libvlc_exception_t ex;
1340         libvlc_exception_init(&ex);
1341
1342         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1343         RETURN_ON_EXCEPTION(this,ex);
1344
1345         switch( index )
1346         {
1347             case ID_video_fullscreen:
1348             {
1349                 int val = p_plugin->get_fullscreen(&ex);
1350                 RETURN_ON_EXCEPTION(this,ex);
1351                 BOOLEAN_TO_NPVARIANT(val, result);
1352                 return INVOKERESULT_NO_ERROR;
1353             }
1354             case ID_video_height:
1355             {
1356                 int val = libvlc_video_get_height(p_md, &ex);
1357                 RETURN_ON_EXCEPTION(this,ex);
1358                 INT32_TO_NPVARIANT(val, result);
1359                 return INVOKERESULT_NO_ERROR;
1360             }
1361             case ID_video_width:
1362             {
1363                 int val = libvlc_video_get_width(p_md, &ex);
1364                 RETURN_ON_EXCEPTION(this,ex);
1365                 INT32_TO_NPVARIANT(val, result);
1366                 return INVOKERESULT_NO_ERROR;
1367             }
1368             case ID_video_aspectratio:
1369             {
1370                 NPUTF8 *psz_aspect = libvlc_video_get_aspect_ratio(p_md, &ex);
1371                 RETURN_ON_EXCEPTION(this,ex);
1372                 if( !psz_aspect )
1373                     return INVOKERESULT_GENERIC_ERROR;
1374
1375                 STRINGZ_TO_NPVARIANT(psz_aspect, result);
1376                 return INVOKERESULT_NO_ERROR;
1377             }
1378             case ID_video_subtitle:
1379             {
1380                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1381                 RETURN_ON_EXCEPTION(this,ex);
1382                 INT32_TO_NPVARIANT(i_spu, result);
1383                 return INVOKERESULT_NO_ERROR;
1384             }
1385             case ID_video_crop:
1386             {
1387                 NPUTF8 *psz_geometry = libvlc_video_get_crop_geometry(p_md, &ex);
1388                 RETURN_ON_EXCEPTION(this,ex);
1389                 if( !psz_geometry )
1390                     return INVOKERESULT_GENERIC_ERROR;
1391
1392                 STRINGZ_TO_NPVARIANT(psz_geometry, result);
1393                 return INVOKERESULT_NO_ERROR;
1394             }
1395             case ID_video_teletext:
1396             {
1397 /*                int i_page = libvlc_video_get_teletext(p_md, &ex);
1398                 RETURN_ON_EXCEPTION(this,ex);
1399                 INT32_TO_NPVARIANT(i_page, result);
1400                 return INVOKERESULT_NO_ERROR;
1401 */
1402                 return INVOKERESULT_NO_SUCH_METHOD;
1403             }
1404             case ID_video_marquee:
1405             {
1406                 InstantObj<LibvlcMarqueeNPObject>( marqueeObj );
1407                 OBJECT_TO_NPVARIANT(NPN_RetainObject(marqueeObj), result);
1408                 return INVOKERESULT_NO_ERROR;
1409             }
1410             case ID_video_logo:
1411             {
1412                 InstantObj<LibvlcLogoNPObject>( logoObj );
1413                 OBJECT_TO_NPVARIANT(NPN_RetainObject(logoObj), result);
1414                 return INVOKERESULT_NO_ERROR;
1415             }
1416             case ID_video_deinterlace:
1417             {
1418                 InstantObj<LibvlcDeinterlaceNPObject>( deintObj );
1419                 OBJECT_TO_NPVARIANT(NPN_RetainObject(deintObj), result);
1420                 return INVOKERESULT_NO_ERROR;
1421             }
1422         }
1423     }
1424     return INVOKERESULT_GENERIC_ERROR;
1425 }
1426
1427 RuntimeNPObject::InvokeResult
1428 LibvlcVideoNPObject::setProperty(int index, const NPVariant &value)
1429 {
1430     /* is plugin still running */
1431     if( isPluginRunning() )
1432     {
1433         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1434         libvlc_exception_t ex;
1435         libvlc_exception_init(&ex);
1436
1437         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1438         RETURN_ON_EXCEPTION(this,ex);
1439
1440         switch( index )
1441         {
1442             case ID_video_fullscreen:
1443             {
1444                 if( ! NPVARIANT_IS_BOOLEAN(value) )
1445                 {
1446                     return INVOKERESULT_INVALID_VALUE;
1447                 }
1448
1449                 int val = NPVARIANT_TO_BOOLEAN(value);
1450                 p_plugin->set_fullscreen(val, &ex);
1451                 RETURN_ON_EXCEPTION(this,ex);
1452                 return INVOKERESULT_NO_ERROR;
1453             }
1454             case ID_video_aspectratio:
1455             {
1456                 char *psz_aspect = NULL;
1457
1458                 if( ! NPVARIANT_IS_STRING(value) )
1459                 {
1460                     return INVOKERESULT_INVALID_VALUE;
1461                 }
1462
1463                 psz_aspect = stringValue(NPVARIANT_TO_STRING(value));
1464                 if( !psz_aspect )
1465                 {
1466                     return INVOKERESULT_GENERIC_ERROR;
1467                 }
1468
1469                 libvlc_video_set_aspect_ratio(p_md, psz_aspect, &ex);
1470                 free(psz_aspect);
1471                 RETURN_ON_EXCEPTION(this,ex);
1472
1473                 return INVOKERESULT_NO_ERROR;
1474             }
1475             case ID_video_subtitle:
1476             {
1477                 if( isNumberValue(value) )
1478                 {
1479                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1480                     RETURN_ON_EXCEPTION(this,ex);
1481
1482                     return INVOKERESULT_NO_ERROR;
1483                 }
1484                 return INVOKERESULT_INVALID_VALUE;
1485             }
1486             case ID_video_crop:
1487             {
1488                 char *psz_geometry = NULL;
1489
1490                 if( ! NPVARIANT_IS_STRING(value) )
1491                 {
1492                     return INVOKERESULT_INVALID_VALUE;
1493                 }
1494
1495                 psz_geometry = stringValue(NPVARIANT_TO_STRING(value));
1496                 if( !psz_geometry )
1497                 {
1498                     return INVOKERESULT_GENERIC_ERROR;
1499                 }
1500
1501                 libvlc_video_set_crop_geometry(p_md, psz_geometry, &ex);
1502                 free(psz_geometry);
1503                 RETURN_ON_EXCEPTION(this,ex);
1504
1505                 return INVOKERESULT_NO_ERROR;
1506             }
1507             case ID_video_teletext:
1508             {
1509                 if( isNumberValue(value) )
1510                 {
1511 /*
1512                     libvlc_video_set_teletext(p_md, numberValue(value), &ex);
1513                     RETURN_ON_EXCEPTION(this,ex);
1514
1515                     return INVOKERESULT_NO_ERROR;
1516 */
1517                     return INVOKERESULT_NO_SUCH_METHOD;
1518                 }
1519                 return INVOKERESULT_INVALID_VALUE;
1520             }
1521         }
1522     }
1523     return INVOKERESULT_GENERIC_ERROR;
1524 }
1525
1526 const NPUTF8 * const LibvlcVideoNPObject::methodNames[] =
1527 {
1528     "toggleFullscreen",
1529     "toggleTeletext",
1530 };
1531 COUNTNAMES(LibvlcVideoNPObject,methodCount,methodNames);
1532
1533 enum LibvlcVideoNPObjectMethodIds
1534 {
1535     ID_video_togglefullscreen,
1536     ID_video_toggleteletext,
1537 };
1538
1539 RuntimeNPObject::InvokeResult
1540 LibvlcVideoNPObject::invoke(int index, const NPVariant *args,
1541                             uint32_t argCount, NPVariant &result)
1542 {
1543     /* is plugin still running */
1544     if( isPluginRunning() )
1545     {
1546         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1547         libvlc_exception_t ex;
1548         libvlc_exception_init(&ex);
1549
1550         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1551         RETURN_ON_EXCEPTION(this,ex);
1552
1553         switch( index )
1554         {
1555             case ID_video_togglefullscreen:
1556             {
1557                 if( argCount == 0 )
1558                 {
1559                     p_plugin->toggle_fullscreen(&ex);
1560                     RETURN_ON_EXCEPTION(this,ex);
1561                     VOID_TO_NPVARIANT(result);
1562                     return INVOKERESULT_NO_ERROR;
1563                 }
1564                 return INVOKERESULT_NO_SUCH_METHOD;
1565             }
1566             case ID_video_toggleteletext:
1567             {
1568                 if( argCount == 0 )
1569                 {
1570                     libvlc_toggle_teletext(p_md);
1571                     VOID_TO_NPVARIANT(result);
1572                     return INVOKERESULT_NO_ERROR;
1573                 }
1574                 return INVOKERESULT_NO_SUCH_METHOD;
1575             }
1576             default:
1577                 return INVOKERESULT_NO_SUCH_METHOD;
1578         }
1579     }
1580     return INVOKERESULT_GENERIC_ERROR;
1581 }
1582
1583 /*
1584 ** implementation of libvlc marquee object
1585 */
1586
1587 const NPUTF8 * const LibvlcMarqueeNPObject::propertyNames[] =
1588 {
1589     "color",
1590     "opacity",
1591     "position",
1592     "refresh",
1593     "size",
1594     "text",
1595     "timeout",
1596     "x",
1597     "y",
1598 };
1599
1600 enum LibvlcMarqueeNPObjectPropertyIds
1601 {
1602     ID_marquee_color,
1603     ID_marquee_opacity,
1604     ID_marquee_position,
1605     ID_marquee_refresh,
1606     ID_marquee_size,
1607     ID_marquee_text,
1608     ID_marquee_timeout,
1609     ID_marquee_x,
1610     ID_marquee_y,
1611 };
1612
1613 COUNTNAMES(LibvlcMarqueeNPObject,propertyCount,propertyNames);
1614
1615 static const unsigned char marquee_idx[] = {
1616     libvlc_marquee_Color,
1617     libvlc_marquee_Opacity,
1618     libvlc_marquee_Position,
1619     libvlc_marquee_Refresh,
1620     libvlc_marquee_Size,
1621     0,
1622     libvlc_marquee_Timeout,
1623     libvlc_marquee_X,
1624     libvlc_marquee_Y,
1625 };
1626
1627 RuntimeNPObject::InvokeResult
1628 LibvlcMarqueeNPObject::getProperty(int index, NPVariant &result)
1629 {
1630     char *psz;
1631
1632     if( !isPluginRunning() )
1633         return INVOKERESULT_GENERIC_ERROR;
1634
1635     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1636     libvlc_exception_t ex;
1637     libvlc_exception_init(&ex);
1638
1639     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1640     RETURN_ON_EXCEPTION(this,ex);
1641
1642     switch( index )
1643     {
1644     case ID_marquee_color:
1645     case ID_marquee_opacity:
1646     case ID_marquee_refresh:
1647     case ID_marquee_timeout:
1648     case ID_marquee_size:
1649     case ID_marquee_x:
1650     case ID_marquee_y:
1651         INT32_TO_NPVARIANT(
1652             libvlc_video_get_marquee_int(p_md, marquee_idx[index], &ex),
1653             result );
1654         RETURN_ON_EXCEPTION(this,ex);
1655         return INVOKERESULT_NO_ERROR;
1656
1657     case ID_marquee_position:
1658         STRINGZ_TO_NPVARIANT( position_bynumber(
1659             libvlc_video_get_marquee_int(p_md, libvlc_marquee_Position, &ex) ),
1660             result );
1661
1662         RETURN_ON_EXCEPTION(this,ex);
1663         break;
1664
1665     case ID_marquee_text:
1666         psz = libvlc_video_get_marquee_string(p_md, libvlc_marquee_Text, &ex);
1667         if( psz )
1668         {
1669             STRINGZ_TO_NPVARIANT(psz, result);
1670             return INVOKERESULT_NO_ERROR;
1671         }
1672         break;
1673     }
1674     return INVOKERESULT_GENERIC_ERROR;
1675 }
1676
1677 RuntimeNPObject::InvokeResult
1678 LibvlcMarqueeNPObject::setProperty(int index, const NPVariant &value)
1679 {
1680     size_t i;
1681
1682     if( !isPluginRunning() )
1683         return INVOKERESULT_GENERIC_ERROR;
1684
1685     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1686     libvlc_exception_t ex;
1687     libvlc_exception_init(&ex);
1688     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1689     RETURN_ON_EXCEPTION(this,ex);
1690
1691     switch( index )
1692     {
1693     case ID_marquee_color:
1694     case ID_marquee_opacity:
1695     case ID_marquee_refresh:
1696     case ID_marquee_timeout:
1697     case ID_marquee_x:
1698     case ID_marquee_y:
1699         if( NPVARIANT_IS_INT32( value ) )
1700         {
1701             libvlc_video_set_marquee_int(p_md, marquee_idx[index],
1702                                          NPVARIANT_TO_INT32( value ), &ex);
1703             RETURN_ON_EXCEPTION(this,ex);
1704             return INVOKERESULT_NO_ERROR;
1705         }
1706         break;
1707
1708     case ID_marquee_position:
1709         if( !NPVARIANT_IS_STRING(value) ||
1710             !position_byname( NPVARIANT_TO_STRING(value).utf8characters, i ) )
1711             return INVOKERESULT_INVALID_VALUE;
1712
1713         libvlc_video_set_marquee_int(p_md, libvlc_marquee_Position, i, &ex);
1714         RETURN_ON_EXCEPTION(this,ex);
1715         return INVOKERESULT_NO_ERROR;
1716
1717     case ID_marquee_text:
1718         if( NPVARIANT_IS_STRING( value ) )
1719         {
1720             char *psz_text = stringValue( NPVARIANT_TO_STRING( value ) );
1721             libvlc_video_set_marquee_string(p_md, libvlc_marquee_Text,
1722                                             psz_text, &ex);
1723             free(psz_text);
1724             RETURN_ON_EXCEPTION(this,ex);
1725             return INVOKERESULT_NO_ERROR;
1726         }
1727         break;
1728     }
1729     return INVOKERESULT_NO_SUCH_METHOD;
1730 }
1731
1732 const NPUTF8 * const LibvlcMarqueeNPObject::methodNames[] =
1733 {
1734     "enable",
1735     "disable",
1736 };
1737 COUNTNAMES(LibvlcMarqueeNPObject,methodCount,methodNames);
1738
1739 enum LibvlcMarqueeNPObjectMethodIds
1740 {
1741     ID_marquee_enable,
1742     ID_marquee_disable,
1743 };
1744
1745 RuntimeNPObject::InvokeResult
1746 LibvlcMarqueeNPObject::invoke(int index, const NPVariant *args,
1747                             uint32_t argCount, NPVariant &result)
1748 {
1749     if( !isPluginRunning() )
1750         return INVOKERESULT_GENERIC_ERROR;
1751
1752     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1753     libvlc_exception_t ex;
1754     libvlc_exception_init(&ex);
1755
1756     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1757     RETURN_ON_EXCEPTION(this,ex);
1758
1759     switch( index )
1760     {
1761     case ID_marquee_enable:
1762     case ID_marquee_disable:
1763         libvlc_video_set_marquee_int(p_md, libvlc_marquee_Enable,
1764                                      index!=ID_marquee_disable, &ex);
1765         RETURN_ON_EXCEPTION(this,ex);
1766         VOID_TO_NPVARIANT(result);
1767         return INVOKERESULT_NO_ERROR;
1768     }
1769     return INVOKERESULT_NO_SUCH_METHOD;
1770 }
1771
1772 const NPUTF8 * const LibvlcLogoNPObject::propertyNames[] = {
1773     "delay",
1774     "repeat",
1775     "opacity",
1776     "position",
1777     "x",
1778     "y",
1779 };
1780 enum LibvlcLogoNPObjectPropertyIds {
1781     ID_logo_delay,
1782     ID_logo_repeat,
1783     ID_logo_opacity,
1784     ID_logo_position,
1785     ID_logo_x,
1786     ID_logo_y,
1787 };
1788 COUNTNAMES(LibvlcLogoNPObject,propertyCount,propertyNames);
1789 static const unsigned char logo_idx[] = {
1790     libvlc_logo_delay,
1791     libvlc_logo_repeat,
1792     libvlc_logo_opacity,
1793     0,
1794     libvlc_logo_x,
1795     libvlc_logo_y,
1796 };
1797
1798 RuntimeNPObject::InvokeResult
1799 LibvlcLogoNPObject::getProperty(int index, NPVariant &result)
1800 {
1801     if( !isPluginRunning() )
1802         return INVOKERESULT_GENERIC_ERROR;
1803
1804     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1805     libvlc_exception_t ex;
1806     libvlc_exception_init(&ex);
1807     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1808     RETURN_ON_EXCEPTION(this,ex);
1809
1810     switch( index )
1811     {
1812     case ID_logo_delay:
1813     case ID_logo_repeat:
1814     case ID_logo_opacity:
1815     case ID_logo_x:
1816     case ID_logo_y:
1817
1818         INT32_TO_NPVARIANT(
1819             libvlc_video_get_logo_int(p_md, logo_idx[index], &ex), result);
1820
1821         RETURN_ON_EXCEPTION(this,ex);
1822         break;
1823
1824     case ID_logo_position:
1825         STRINGZ_TO_NPVARIANT( position_bynumber(
1826             libvlc_video_get_logo_int(p_md, libvlc_logo_position, &ex) ),
1827             result );
1828
1829         RETURN_ON_EXCEPTION(this,ex);
1830         break;
1831     default:
1832         return INVOKERESULT_GENERIC_ERROR;
1833     }
1834     return INVOKERESULT_NO_ERROR;
1835 }
1836
1837 RuntimeNPObject::InvokeResult
1838 LibvlcLogoNPObject::setProperty(int index, const NPVariant &value)
1839 {
1840     size_t i;
1841
1842     if( !isPluginRunning() )
1843         return INVOKERESULT_GENERIC_ERROR;
1844
1845     VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1846     libvlc_exception_t ex;
1847     libvlc_exception_init(&ex);
1848
1849     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1850     RETURN_ON_EXCEPTION(this,ex);
1851
1852     switch( index )
1853     {
1854     case ID_logo_delay:
1855     case ID_logo_repeat:
1856     case ID_logo_opacity:
1857     case ID_logo_x:
1858     case ID_logo_y:
1859         if( !NPVARIANT_IS_INT32(value) )
1860             return INVOKERESULT_INVALID_VALUE;
1861
1862         libvlc_video_set_logo_int(p_md, logo_idx[index],
1863                                   NPVARIANT_TO_INT32( value ), &ex);
1864
1865         RETURN_ON_EXCEPTION(this,ex);
1866         break;
1867
1868     case ID_logo_position:
1869         if( !NPVARIANT_IS_STRING(value) ||
1870             !position_byname( NPVARIANT_TO_STRING(value).utf8characters, i ) )
1871             return INVOKERESULT_INVALID_VALUE;
1872
1873         libvlc_video_set_logo_int(p_md, libvlc_logo_position, i, &ex);
1874
1875         RETURN_ON_EXCEPTION(this,ex);
1876         break;
1877     default:
1878         return INVOKERESULT_GENERIC_ERROR;
1879     }
1880     return INVOKERESULT_NO_ERROR;
1881 }
1882
1883
1884 const NPUTF8 * const LibvlcLogoNPObject::methodNames[] = {
1885     "enable",
1886     "disable",
1887     "file",
1888 };
1889 enum LibvlcLogoNPObjectMethodIds {
1890     ID_logo_enable,
1891     ID_logo_disable,
1892     ID_logo_file,
1893 };
1894 COUNTNAMES(LibvlcLogoNPObject,methodCount,methodNames);
1895
1896 RuntimeNPObject::InvokeResult
1897 LibvlcLogoNPObject::invoke(int index, const NPVariant *args,
1898                            uint32_t argCount, NPVariant &result)
1899 {
1900     char *buf, *h;
1901     size_t i, len;
1902
1903     if( !isPluginRunning() )
1904         return INVOKERESULT_GENERIC_ERROR;
1905
1906     libvlc_exception_t ex;
1907     libvlc_exception_init(&ex);
1908     libvlc_media_player_t *p_md = getPrivate<VlcPlugin>()->getMD(&ex);
1909     RETURN_ON_EXCEPTION(this,ex);
1910
1911     switch( index )
1912     {
1913     case ID_logo_enable:
1914     case ID_logo_disable:
1915         if( argCount != 0 )
1916             return INVOKERESULT_GENERIC_ERROR;
1917
1918         libvlc_video_set_logo_int(p_md, libvlc_logo_enable,
1919                                   index != ID_logo_disable, &ex);
1920         RETURN_ON_EXCEPTION(this,ex);
1921         VOID_TO_NPVARIANT(result);
1922         break;
1923
1924     case ID_logo_file:
1925         if( argCount == 0 )
1926             return INVOKERESULT_GENERIC_ERROR;
1927
1928         for( len=0,i=0;i<argCount;++i )
1929         {
1930             if( !NPVARIANT_IS_STRING(args[i]) )
1931                 return INVOKERESULT_INVALID_VALUE;
1932             len+=NPVARIANT_TO_STRING(args[i]).utf8length+1;
1933         }
1934
1935         buf = (char *)malloc( len+1 );
1936         if( !buf )
1937             return INVOKERESULT_OUT_OF_MEMORY;
1938
1939         for( h=buf,i=0;i<argCount;++i )
1940         {
1941             if(i) *h++=';';
1942             len=NPVARIANT_TO_STRING(args[i]).utf8length;
1943             memcpy(h,NPVARIANT_TO_STRING(args[i]).utf8characters,len);
1944             h+=len;
1945         }
1946         *h='\0';
1947
1948         libvlc_video_set_logo_string(p_md, libvlc_logo_file, buf, &ex);
1949         free( buf );
1950         RETURN_ON_EXCEPTION(this,ex);
1951         VOID_TO_NPVARIANT(result);
1952         break;
1953     default:
1954         return INVOKERESULT_NO_SUCH_METHOD;
1955     }
1956     return INVOKERESULT_NO_ERROR;
1957 }
1958
1959
1960 const NPUTF8 * const LibvlcDeinterlaceNPObject::propertyNames[] = {
1961 };
1962 enum LibvlcDeinterlaceNPObjectPropertyIds {
1963 };
1964 COUNTNAMES(LibvlcDeinterlaceNPObject,propertyCount,propertyNames);
1965
1966 RuntimeNPObject::InvokeResult
1967 LibvlcDeinterlaceNPObject::getProperty(int index, NPVariant &result)
1968 {
1969     return INVOKERESULT_GENERIC_ERROR;
1970 }
1971
1972 RuntimeNPObject::InvokeResult
1973 LibvlcDeinterlaceNPObject::setProperty(int index, const NPVariant &value)
1974 {
1975     return INVOKERESULT_GENERIC_ERROR;
1976 }
1977
1978
1979 const NPUTF8 * const LibvlcDeinterlaceNPObject::methodNames[] = {
1980     "enable",
1981     "disable",
1982 };
1983 enum LibvlcDeinterlaceNPObjectMethodIds {
1984     ID_deint_enable,
1985     ID_deint_disable,
1986 };
1987 COUNTNAMES(LibvlcDeinterlaceNPObject,methodCount,methodNames);
1988
1989 RuntimeNPObject::InvokeResult
1990 LibvlcDeinterlaceNPObject::invoke(int index, const NPVariant *args,
1991                            uint32_t argCount, NPVariant &result)
1992 {
1993     char *psz;
1994
1995     if( !isPluginRunning() )
1996         return INVOKERESULT_GENERIC_ERROR;
1997
1998     libvlc_exception_t ex;
1999     libvlc_exception_init(&ex);
2000     libvlc_media_player_t *p_md = getPrivate<VlcPlugin>()->getMD(&ex);
2001     RETURN_ON_EXCEPTION(this,ex);
2002
2003     switch( index )
2004     {
2005     case ID_deint_disable:
2006         libvlc_video_set_deinterlace(p_md, 0, "", &ex);
2007         RETURN_ON_EXCEPTION(this,ex);
2008         break;
2009
2010     case ID_deint_enable:
2011         if( argCount != 1 || !NPVARIANT_IS_STRING( args[0] ) )
2012             return INVOKERESULT_INVALID_VALUE;
2013
2014         psz = stringValue( NPVARIANT_TO_STRING( args[0] ) );
2015         libvlc_video_set_deinterlace(p_md, 1, psz, &ex);
2016         free(psz);
2017         RETURN_ON_EXCEPTION(this,ex);
2018         break;
2019
2020     default:
2021         return INVOKERESULT_NO_SUCH_METHOD;
2022     }
2023     return INVOKERESULT_NO_ERROR;
2024 }
2025