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