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