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