]> git.sesse.net Git - vlc/blob - projects/mozilla/control/npolibvlc.cpp
mozilla plugin: cosmetics.
[vlc] / projects / mozilla / control / npolibvlc.cpp
1 /*****************************************************************************
2  * npolibvlc.cpp: official Javascript APIs
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  *
6  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
7  *          JP Dinger <jpd@m2x.nl>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include "config.h"
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 /* Mozilla stuff */
31 #ifdef HAVE_MOZILLA_CONFIG_H
32 #   include <mozilla-config.h>
33 #endif
34
35 #include "vlcplugin.h"
36 #include "npolibvlc.h"
37
38 /*
39 ** Local helper macros and function
40 */
41 #define COUNTNAMES(a,b,c) const int a::b = sizeof(a::c)/sizeof(NPUTF8 *)
42 #define RETURN_ON_EXCEPTION(this,ex) \
43     do { if( libvlc_exception_raised(&ex) ) \
44     { \
45         NPN_SetException(this, libvlc_exception_get_message(&ex)); \
46         libvlc_exception_clear(&ex); \
47         return INVOKERESULT_GENERIC_ERROR; \
48     } } while(false)
49
50 /*
51 ** implementation of libvlc root object
52 */
53
54 LibvlcRootNPObject::~LibvlcRootNPObject()
55 {
56     /*
57     ** When the plugin is destroyed, firefox takes it upon itself to
58     ** destroy all 'live' script objects and ignores refcounting.
59     ** Therefore we cannot safely assume that refcounting will control
60     ** lifespan of objects. Hence they are only lazily created on
61     ** request, so that firefox can take ownership, and are not released
62     ** when the plugin is destroyed.
63     */
64     if( isValid() )
65     {
66         if( audioObj    ) NPN_ReleaseObject(audioObj);
67         if( inputObj    ) NPN_ReleaseObject(inputObj);
68         if( playlistObj ) NPN_ReleaseObject(playlistObj);
69         if( videoObj    ) NPN_ReleaseObject(videoObj);
70     }
71 }
72
73 const NPUTF8 * const LibvlcRootNPObject::propertyNames[] =
74 {
75     "audio",
76     "input",
77     "playlist",
78     "subtitle",
79     "video",
80     "VersionInfo",
81 };
82 COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames);
83
84 enum LibvlcRootNPObjectPropertyIds
85 {
86     ID_root_audio = 0,
87     ID_root_input,
88     ID_root_playlist,
89     ID_root_subtitle,
90     ID_root_video,
91     ID_root_VersionInfo,
92 };
93
94 RuntimeNPObject::InvokeResult
95 LibvlcRootNPObject::getProperty(int index, NPVariant &result)
96 {
97     /* is plugin still running */
98     if( isPluginRunning() )
99     {
100         switch( index )
101         {
102             case ID_root_audio:
103                 // create child object in lazyman fashion to avoid
104                 // ownership problem with firefox
105                 if( ! audioObj )
106                     audioObj = NPN_CreateObject(_instance,
107                              RuntimeNPClass<LibvlcAudioNPObject>::getClass());
108                 OBJECT_TO_NPVARIANT(NPN_RetainObject(audioObj), result);
109                 return INVOKERESULT_NO_ERROR;
110             case ID_root_input:
111                 // create child object in lazyman fashion to avoid
112                 // ownership problem with firefox
113                 if( ! inputObj )
114                     inputObj = NPN_CreateObject(_instance,
115                              RuntimeNPClass<LibvlcInputNPObject>::getClass());
116                 OBJECT_TO_NPVARIANT(NPN_RetainObject(inputObj), result);
117                 return INVOKERESULT_NO_ERROR;
118             case ID_root_playlist:
119                 // create child object in lazyman fashion to avoid
120                 // ownership problem with firefox
121                 if( ! playlistObj )
122                     playlistObj = NPN_CreateObject(_instance,
123                           RuntimeNPClass<LibvlcPlaylistNPObject>::getClass());
124                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistObj), result);
125                 return INVOKERESULT_NO_ERROR;
126             case ID_root_subtitle:
127                 // create child object in lazyman fashion to avoid
128                 // ownership problem with firefox
129                 if( ! subtitleObj )
130                     subtitleObj = NPN_CreateObject(_instance,
131                              RuntimeNPClass<LibvlcSubtitleNPObject>::getClass());
132                 OBJECT_TO_NPVARIANT(NPN_RetainObject(subtitleObj), result);
133                 return INVOKERESULT_NO_ERROR;
134             case ID_root_video:
135                 // create child object in lazyman fashion to avoid
136                 // ownership problem with firefox
137                 if( ! videoObj )
138                     videoObj = NPN_CreateObject(_instance,
139                              RuntimeNPClass<LibvlcVideoNPObject>::getClass());
140                 OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);
141                 return INVOKERESULT_NO_ERROR;
142             case ID_root_VersionInfo:
143                 return invokeResultString(libvlc_get_version(),result);
144             default:
145                 ;
146         }
147     }
148     return INVOKERESULT_GENERIC_ERROR;
149 }
150
151 const NPUTF8 * const LibvlcRootNPObject::methodNames[] =
152 {
153     "versionInfo",
154 };
155 COUNTNAMES(LibvlcRootNPObject,methodCount,methodNames);
156
157 enum LibvlcRootNPObjectMethodIds
158 {
159     ID_root_versionInfo,
160 };
161
162 RuntimeNPObject::InvokeResult LibvlcRootNPObject::invoke(int index,
163                   const NPVariant *args, uint32_t argCount, NPVariant &result)
164 {
165     /* is plugin still running */
166     if( isPluginRunning() )
167     {
168         libvlc_exception_t ex;
169         libvlc_exception_init(&ex);
170
171         switch( index )
172         {
173             case ID_root_versionInfo:
174                 if( 0 != argCount )
175                     return INVOKERESULT_NO_SUCH_METHOD;
176                 return invokeResultString(libvlc_get_version(),result);
177             default:
178                 ;
179         }
180     }
181     return INVOKERESULT_GENERIC_ERROR;
182 }
183
184 /*
185 ** implementation of libvlc audio object
186 */
187
188 const NPUTF8 * const LibvlcAudioNPObject::propertyNames[] =
189 {
190     "mute",
191     "volume",
192     "track",
193     "count",
194     "channel",
195 };
196 COUNTNAMES(LibvlcAudioNPObject,propertyCount,propertyNames);
197
198 enum LibvlcAudioNPObjectPropertyIds
199 {
200     ID_audio_mute,
201     ID_audio_volume,
202     ID_audio_track,
203     ID_audio_count,
204     ID_audio_channel,
205 };
206
207 RuntimeNPObject::InvokeResult
208 LibvlcAudioNPObject::getProperty(int index, NPVariant &result)
209 {
210     /* is plugin still running */
211     if( isPluginRunning() )
212     {
213         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
214         libvlc_exception_t ex;
215         libvlc_exception_init(&ex);
216
217         switch( index )
218         {
219             case ID_audio_mute:
220             {
221                 bool muted = libvlc_audio_get_mute(p_plugin->getVLC(), &ex);
222                 RETURN_ON_EXCEPTION(this,ex);
223                 BOOLEAN_TO_NPVARIANT(muted, result);
224                 return INVOKERESULT_NO_ERROR;
225             }
226             case ID_audio_volume:
227             {
228                 int volume = libvlc_audio_get_volume(p_plugin->getVLC(), &ex);
229                 RETURN_ON_EXCEPTION(this,ex);
230                 INT32_TO_NPVARIANT(volume, result);
231                 return INVOKERESULT_NO_ERROR;
232             }
233             case ID_audio_track:
234             {
235                 libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
236                 RETURN_ON_EXCEPTION(this,ex);
237                 int track = libvlc_audio_get_track(p_md, &ex);
238                 RETURN_ON_EXCEPTION(this,ex);
239                 INT32_TO_NPVARIANT(track, result);
240                 return INVOKERESULT_NO_ERROR;
241             }
242             case ID_audio_count:
243             {
244                 libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
245                 RETURN_ON_EXCEPTION(this,ex);
246                 // get the number of audio track available
247                 int i_track = libvlc_audio_get_track_count(p_md, &ex);
248                 RETURN_ON_EXCEPTION(this,ex);
249                 // return it
250                 INT32_TO_NPVARIANT(i_track, result);
251                 return INVOKERESULT_NO_ERROR;
252             }
253             case ID_audio_channel:
254             {
255                 int channel = libvlc_audio_get_channel(p_plugin->getVLC(), &ex);
256                 RETURN_ON_EXCEPTION(this,ex);
257                 INT32_TO_NPVARIANT(channel, result);
258                 return INVOKERESULT_NO_ERROR;
259             }
260             default:
261                 ;
262         }
263     }
264     return INVOKERESULT_GENERIC_ERROR;
265 }
266
267 RuntimeNPObject::InvokeResult
268 LibvlcAudioNPObject::setProperty(int index, const NPVariant &value)
269 {
270     /* is plugin still running */
271     if( isPluginRunning() )
272     {
273         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
274         libvlc_exception_t ex;
275         libvlc_exception_init(&ex);
276
277         switch( index )
278         {
279             case ID_audio_mute:
280                 if( NPVARIANT_IS_BOOLEAN(value) )
281                 {
282                     libvlc_audio_set_mute(p_plugin->getVLC(),
283                                           NPVARIANT_TO_BOOLEAN(value), &ex);
284                     RETURN_ON_EXCEPTION(this,ex);
285                     return INVOKERESULT_NO_ERROR;
286                 }
287                 return INVOKERESULT_INVALID_VALUE;
288             case ID_audio_volume:
289                 if( isNumberValue(value) )
290                 {
291                     libvlc_audio_set_volume(p_plugin->getVLC(),
292                                             numberValue(value), &ex);
293                     RETURN_ON_EXCEPTION(this,ex);
294                     return INVOKERESULT_NO_ERROR;
295                 }
296                 return INVOKERESULT_INVALID_VALUE;
297             case ID_audio_track:
298                 if( isNumberValue(value) )
299                 {
300                     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
301                     RETURN_ON_EXCEPTION(this,ex);
302                     libvlc_audio_set_track(p_md, numberValue(value), &ex);
303                     RETURN_ON_EXCEPTION(this,ex);
304                     return INVOKERESULT_NO_ERROR;
305                 }
306                 return INVOKERESULT_INVALID_VALUE;
307             case ID_audio_channel:
308                 if( isNumberValue(value) )
309                 {
310                     libvlc_audio_set_channel(p_plugin->getVLC(),
311                                              numberValue(value), &ex);
312                     RETURN_ON_EXCEPTION(this,ex);
313                     return INVOKERESULT_NO_ERROR;
314                 }
315                 return INVOKERESULT_INVALID_VALUE;
316             default:
317                 ;
318         }
319     }
320     return INVOKERESULT_GENERIC_ERROR;
321 }
322
323 const NPUTF8 * const LibvlcAudioNPObject::methodNames[] =
324 {
325     "toggleMute",
326     "description",
327 };
328 COUNTNAMES(LibvlcAudioNPObject,methodCount,methodNames);
329
330 enum LibvlcAudioNPObjectMethodIds
331 {
332     ID_audio_togglemute,
333     ID_audio_description,
334 };
335
336 RuntimeNPObject::InvokeResult
337 LibvlcAudioNPObject::invoke(int index, const NPVariant *args,
338                             uint32_t argCount, NPVariant &result)
339 {
340     /* is plugin still running */
341     if( isPluginRunning() )
342     {
343         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
344         libvlc_exception_t ex;
345         libvlc_exception_init(&ex);
346
347         switch( index )
348         {
349             case ID_audio_togglemute:
350                 if( argCount == 0 )
351                 {
352                     libvlc_audio_toggle_mute(p_plugin->getVLC(), &ex);
353                     RETURN_ON_EXCEPTION(this,ex);
354                     VOID_TO_NPVARIANT(result);
355                     return INVOKERESULT_NO_ERROR;
356                 }
357                 return INVOKERESULT_NO_SUCH_METHOD;
358             case ID_audio_description:
359             {
360                 if( argCount == 1)
361                 {
362                     char *psz_name;
363                     int i_trackID, i_limit, i;
364                     libvlc_track_description_t *p_trackDesc;
365
366                     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
367                     RETURN_ON_EXCEPTION(this,ex);
368
369                     /* get tracks description */
370                     p_trackDesc = libvlc_audio_get_track_description(p_md, &ex);
371                     RETURN_ON_EXCEPTION(this,ex);
372                     if( !p_trackDesc )
373                         return INVOKERESULT_GENERIC_ERROR;
374
375                     /* get the number of track available */
376                     i_limit = libvlc_audio_get_track_count(p_md, &ex);
377                     RETURN_ON_EXCEPTION(this,ex);
378
379                     /* check if a number is given by the user
380                      * and get the track number */
381                     if( isNumberValue(args[0]) )
382                         i_trackID = numberValue(args[0]);
383                     else
384                         return INVOKERESULT_INVALID_VALUE;
385
386                     /* if bad number is given return invalid value */
387                     if ( ( i_trackID > ( i_limit - 1 ) ) || ( i_trackID < 0 ) )
388                         return INVOKERESULT_INVALID_VALUE;
389
390                     /* get the good trackDesc */
391                     for( i = 0 ; i < i_trackID ; i++ )
392                     {
393                         p_trackDesc = p_trackDesc->p_next;
394                     }
395                     psz_name = p_trackDesc->psz_name;
396
397                     /* display the name of the track chosen */
398                     return invokeResultString( psz_name, result );
399                 }
400                 return INVOKERESULT_NO_SUCH_METHOD;
401             }
402             default:
403                 ;
404         }
405     }
406     return INVOKERESULT_GENERIC_ERROR;
407 }
408
409 /*
410 ** implementation of libvlc input object
411 */
412
413 const NPUTF8 * const LibvlcInputNPObject::propertyNames[] =
414 {
415     "length",
416     "position",
417     "time",
418     "state",
419     "rate",
420     "fps",
421     "hasVout",
422 };
423 COUNTNAMES(LibvlcInputNPObject,propertyCount,propertyNames);
424
425 enum LibvlcInputNPObjectPropertyIds
426 {
427     ID_input_length,
428     ID_input_position,
429     ID_input_time,
430     ID_input_state,
431     ID_input_rate,
432     ID_input_fps,
433     ID_input_hasvout,
434 };
435
436 RuntimeNPObject::InvokeResult
437 LibvlcInputNPObject::getProperty(int index, NPVariant &result)
438 {
439     /* is plugin still running */
440     if( isPluginRunning() )
441     {
442         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
443         libvlc_exception_t ex;
444         libvlc_exception_init(&ex);
445
446         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
447         if( libvlc_exception_raised(&ex) )
448         {
449             if( index != ID_input_state )
450             {
451                 NPN_SetException(this, libvlc_exception_get_message(&ex));
452                 libvlc_exception_clear(&ex);
453                 return INVOKERESULT_GENERIC_ERROR;
454             }
455             else
456             {
457                 /* for input state, return CLOSED rather than an exception */
458                 INT32_TO_NPVARIANT(0, result);
459                 libvlc_exception_clear(&ex);
460                 return INVOKERESULT_NO_ERROR;
461             }
462         }
463
464         switch( index )
465         {
466             case ID_input_length:
467             {
468                 double val = (double)libvlc_media_player_get_length(p_md, &ex);
469                 RETURN_ON_EXCEPTION(this,ex);
470                 DOUBLE_TO_NPVARIANT(val, result);
471                 return INVOKERESULT_NO_ERROR;
472             }
473             case ID_input_position:
474             {
475                 double val = libvlc_media_player_get_position(p_md, &ex);
476                 RETURN_ON_EXCEPTION(this,ex);
477                 DOUBLE_TO_NPVARIANT(val, result);
478                 return INVOKERESULT_NO_ERROR;
479             }
480             case ID_input_time:
481             {
482                 double val = (double)libvlc_media_player_get_time(p_md, &ex);
483                 RETURN_ON_EXCEPTION(this,ex);
484                 DOUBLE_TO_NPVARIANT(val, result);
485                 return INVOKERESULT_NO_ERROR;
486             }
487             case ID_input_state:
488             {
489                 int val = libvlc_media_player_get_state(p_md, &ex);
490                 RETURN_ON_EXCEPTION(this,ex);
491                 INT32_TO_NPVARIANT(val, result);
492                 return INVOKERESULT_NO_ERROR;
493             }
494             case ID_input_rate:
495             {
496                 float val = libvlc_media_player_get_rate(p_md, &ex);
497                 RETURN_ON_EXCEPTION(this,ex);
498                 DOUBLE_TO_NPVARIANT(val, result);
499                 return INVOKERESULT_NO_ERROR;
500             }
501             case ID_input_fps:
502             {
503                 double val = libvlc_media_player_get_fps(p_md, &ex);
504                 RETURN_ON_EXCEPTION(this,ex);
505                 DOUBLE_TO_NPVARIANT(val, result);
506                 return INVOKERESULT_NO_ERROR;
507             }
508             case ID_input_hasvout:
509             {
510                 bool val = p_plugin->player_has_vout(&ex);
511                 RETURN_ON_EXCEPTION(this,ex);
512                 BOOLEAN_TO_NPVARIANT(val, result);
513                 return INVOKERESULT_NO_ERROR;
514             }
515             default:
516                 ;
517         }
518     }
519     return INVOKERESULT_GENERIC_ERROR;
520 }
521
522 RuntimeNPObject::InvokeResult
523 LibvlcInputNPObject::setProperty(int index, const NPVariant &value)
524 {
525     /* is plugin still running */
526     if( isPluginRunning() )
527     {
528         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
529         libvlc_exception_t ex;
530         libvlc_exception_init(&ex);
531
532         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
533         RETURN_ON_EXCEPTION(this,ex);
534
535         switch( index )
536         {
537             case ID_input_position:
538             {
539                 if( ! NPVARIANT_IS_DOUBLE(value) )
540                 {
541                     return INVOKERESULT_INVALID_VALUE;
542                 }
543
544                 float val = (float)NPVARIANT_TO_DOUBLE(value);
545                 libvlc_media_player_set_position(p_md, val, &ex);
546                 RETURN_ON_EXCEPTION(this,ex);
547                 return INVOKERESULT_NO_ERROR;
548             }
549             case ID_input_time:
550             {
551                 int64_t val;
552                 if( NPVARIANT_IS_INT32(value) )
553                     val = (int64_t)NPVARIANT_TO_INT32(value);
554                 else if( NPVARIANT_IS_DOUBLE(value) )
555                     val = (int64_t)NPVARIANT_TO_DOUBLE(value);
556                 else
557                 {
558                     return INVOKERESULT_INVALID_VALUE;
559                 }
560
561                 libvlc_media_player_set_time(p_md, val, &ex);
562                 RETURN_ON_EXCEPTION(this,ex);
563                 return INVOKERESULT_NO_ERROR;
564             }
565             case ID_input_rate:
566             {
567                 float val;
568                 if( NPVARIANT_IS_INT32(value) )
569                     val = (float)NPVARIANT_TO_INT32(value);
570                 else if( NPVARIANT_IS_DOUBLE(value) )
571                     val = (float)NPVARIANT_TO_DOUBLE(value);
572                 else
573                 {
574                     return INVOKERESULT_INVALID_VALUE;
575                 }
576
577                 libvlc_media_player_set_rate(p_md, val, &ex);
578                 RETURN_ON_EXCEPTION(this,ex);
579                 return INVOKERESULT_NO_ERROR;
580             }
581             default:
582                 ;
583         }
584     }
585     return INVOKERESULT_GENERIC_ERROR;
586 }
587
588 const NPUTF8 * const LibvlcInputNPObject::methodNames[] =
589 {
590     /* no methods */
591 };
592
593 COUNTNAMES(LibvlcInputNPObject,methodCount,methodNames);
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                 // create child object in lazyman fashion to avoid
742                 // ownership problem with firefox
743                 if( ! playlistItemsObj )
744                     playlistItemsObj =
745                         NPN_CreateObject(_instance, RuntimeNPClass<
746                         LibvlcPlaylistItemsNPObject>::getClass());
747                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistItemsObj), result);
748                 return INVOKERESULT_NO_ERROR;
749             }
750             default:
751                 ;
752         }
753     }
754     return INVOKERESULT_GENERIC_ERROR;
755 }
756
757 const NPUTF8 * const LibvlcPlaylistNPObject::methodNames[] =
758 {
759     "add",
760     "play",
761     "playItem",
762     "togglePause",
763     "stop",
764     "next",
765     "prev",
766     "clear", /* deprecated */
767     "removeItem", /* deprecated */
768 };
769 COUNTNAMES(LibvlcPlaylistNPObject,methodCount,methodNames);
770
771 enum LibvlcPlaylistNPObjectMethodIds
772 {
773     ID_playlist_add,
774     ID_playlist_play,
775     ID_playlist_playItem,
776     ID_playlist_togglepause,
777     ID_playlist_stop,
778     ID_playlist_next,
779     ID_playlist_prev,
780     ID_playlist_clear,
781     ID_playlist_removeitem
782 };
783
784 RuntimeNPObject::InvokeResult
785 LibvlcPlaylistNPObject::invoke(int index, const NPVariant *args,
786                                uint32_t argCount, NPVariant &result)
787 {
788     /* is plugin still running */
789     if( isPluginRunning() )
790     {
791         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
792         libvlc_exception_t ex;
793         libvlc_exception_init(&ex);
794
795         switch( index )
796         {
797             // XXX FIXME this needs squashing into something much smaller
798             case ID_playlist_add:
799             {
800                 if( (argCount < 1) || (argCount > 3) )
801                     return INVOKERESULT_NO_SUCH_METHOD;
802                 if( !NPVARIANT_IS_STRING(args[0]) )
803                     return INVOKERESULT_NO_SUCH_METHOD;
804
805                 // grab URL
806                 char *s = stringValue(NPVARIANT_TO_STRING(args[0]));
807                 if( !s )
808                     return INVOKERESULT_OUT_OF_MEMORY;
809
810                 char *url = p_plugin->getAbsoluteURL(s);
811                 if( url )
812                     free(s);
813                 else
814                     // problem with combining url, use argument
815                     url = s;
816
817                 char *name = NULL;
818
819                 // grab name if available
820                 if( argCount > 1 )
821                 {
822                     if( NPVARIANT_IS_NULL(args[1]) )
823                     {
824                         // do nothing
825                     }
826                     else if( NPVARIANT_IS_STRING(args[1]) )
827                     {
828                         name = stringValue(NPVARIANT_TO_STRING(args[1]));
829                     }
830                     else
831                     {
832                         free(url);
833                         return INVOKERESULT_INVALID_VALUE;
834                     }
835                 }
836
837                 int i_options = 0;
838                 char** ppsz_options = NULL;
839
840                 // grab options if available
841                 if( argCount > 2 )
842                 {
843                     if( NPVARIANT_IS_NULL(args[2]) )
844                     {
845                         // do nothing
846                     }
847                     else if( NPVARIANT_IS_STRING(args[2]) )
848                     {
849                         parseOptions(NPVARIANT_TO_STRING(args[2]),
850                                      &i_options, &ppsz_options);
851
852                     }
853                     else if( NPVARIANT_IS_OBJECT(args[2]) )
854                     {
855                         parseOptions(NPVARIANT_TO_OBJECT(args[2]),
856                                      &i_options, &ppsz_options);
857                     }
858                     else
859                     {
860                         free(url);
861                         free(name);
862                         return INVOKERESULT_INVALID_VALUE;
863                     }
864                 }
865
866                 int item = p_plugin->playlist_add_extended_untrusted(url, name,
867                       i_options, const_cast<const char **>(ppsz_options), &ex);
868                 free(url);
869                 free(name);
870                 for( int i=0; i< i_options; ++i )
871                 {
872                     free(ppsz_options[i]);
873                 }
874                 free(ppsz_options);
875
876                 RETURN_ON_EXCEPTION(this,ex);
877                 INT32_TO_NPVARIANT(item, result);
878                 return INVOKERESULT_NO_ERROR;
879             }
880             case ID_playlist_play:
881                 if( argCount == 0 )
882                 {
883                     p_plugin->playlist_play(&ex);
884                     RETURN_ON_EXCEPTION(this,ex);
885                     VOID_TO_NPVARIANT(result);
886                     return INVOKERESULT_NO_ERROR;
887                 }
888                 return INVOKERESULT_NO_SUCH_METHOD;
889             case ID_playlist_playItem:
890                 if( (argCount == 1) && isNumberValue(args[0]) )
891                 {
892                     p_plugin->playlist_play_item(numberValue(args[0]),&ex);
893                     RETURN_ON_EXCEPTION(this,ex);
894                     VOID_TO_NPVARIANT(result);
895                     return INVOKERESULT_NO_ERROR;
896                 }
897                 return INVOKERESULT_NO_SUCH_METHOD;
898             case ID_playlist_togglepause:
899                 if( argCount == 0 )
900                 {
901                     p_plugin->playlist_pause(&ex);
902                     RETURN_ON_EXCEPTION(this,ex);
903                     VOID_TO_NPVARIANT(result);
904                     return INVOKERESULT_NO_ERROR;
905                 }
906                 return INVOKERESULT_NO_SUCH_METHOD;
907             case ID_playlist_stop:
908                 if( argCount == 0 )
909                 {
910                     p_plugin->playlist_stop(&ex);
911                     RETURN_ON_EXCEPTION(this,ex);
912                     VOID_TO_NPVARIANT(result);
913                     return INVOKERESULT_NO_ERROR;
914                 }
915                 return INVOKERESULT_NO_SUCH_METHOD;
916             case ID_playlist_next:
917                 if( argCount == 0 )
918                 {
919                     p_plugin->playlist_next(&ex);
920                     RETURN_ON_EXCEPTION(this,ex);
921                     VOID_TO_NPVARIANT(result);
922                     return INVOKERESULT_NO_ERROR;
923                 }
924                 return INVOKERESULT_NO_SUCH_METHOD;
925             case ID_playlist_prev:
926                 if( argCount == 0 )
927                 {
928                     p_plugin->playlist_prev(&ex);
929                     RETURN_ON_EXCEPTION(this,ex);
930                     VOID_TO_NPVARIANT(result);
931                     return INVOKERESULT_NO_ERROR;
932                 }
933                 return INVOKERESULT_NO_SUCH_METHOD;
934             case ID_playlist_clear: /* deprecated */
935                 if( argCount == 0 )
936                 {
937                     p_plugin->playlist_clear(&ex);
938                     RETURN_ON_EXCEPTION(this,ex);
939                     VOID_TO_NPVARIANT(result);
940                     return INVOKERESULT_NO_ERROR;
941                 }
942                 return INVOKERESULT_NO_SUCH_METHOD;
943             case ID_playlist_removeitem: /* deprecated */
944                 if( (argCount == 1) && isNumberValue(args[0]) )
945                 {
946                     p_plugin->playlist_delete_item(numberValue(args[0]), &ex);
947                     RETURN_ON_EXCEPTION(this,ex);
948                     VOID_TO_NPVARIANT(result);
949                     return INVOKERESULT_NO_ERROR;
950                 }
951                 return INVOKERESULT_NO_SUCH_METHOD;
952             default:
953                 ;
954         }
955     }
956     return INVOKERESULT_GENERIC_ERROR;
957 }
958
959 // XXX FIXME The new playlist_add creates a media instance and feeds it
960 // XXX FIXME these options one at a time, so this hunk of code does lots
961 // XXX FIXME of unnecessairy work. Break out something that can do one
962 // XXX FIXME option at a time and doesn't need to realloc().
963 // XXX FIXME Same for the other version of parseOptions.
964
965 void LibvlcPlaylistNPObject::parseOptions(const NPString &nps,
966                                          int *i_options, char*** ppsz_options)
967 {
968     if( nps.utf8length )
969     {
970         char *s = stringValue(nps);
971         char *val = s;
972         if( val )
973         {
974             long capacity = 16;
975             char **options = (char **)malloc(capacity*sizeof(char *));
976             if( options )
977             {
978                 int nOptions = 0;
979
980                 char *end = val + nps.utf8length;
981                 while( val < end )
982                 {
983                     // skip leading blanks
984                     while( (val < end)
985                         && ((*val == ' ' ) || (*val == '\t')) )
986                         ++val;
987
988                     char *start = val;
989                     // skip till we get a blank character
990                     while( (val < end)
991                         && (*val != ' ' )
992                         && (*val != '\t') )
993                     {
994                         char c = *(val++);
995                         if( ('\'' == c) || ('"' == c) )
996                         {
997                             // skip till end of string
998                             while( (val < end) && (*(val++) != c ) );
999                         }
1000                     }
1001
1002                     if( val > start )
1003                     {
1004                         if( nOptions == capacity )
1005                         {
1006                             capacity += 16;
1007                             char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1008                             if( ! moreOptions )
1009                             {
1010                                 /* failed to allocate more memory */
1011                                 free(s);
1012                                 /* return what we got so far */
1013                                 *i_options = nOptions;
1014                                 *ppsz_options = options;
1015                                 return;
1016                             }
1017                             options = moreOptions;
1018                         }
1019                         *(val++) = '\0';
1020                         options[nOptions++] = strdup(start);
1021                     }
1022                     else
1023                         // must be end of string
1024                         break;
1025                 }
1026                 *i_options = nOptions;
1027                 *ppsz_options = options;
1028             }
1029             free(s);
1030         }
1031     }
1032 }
1033
1034 // XXX FIXME See comment at the other parseOptions variant.
1035 void LibvlcPlaylistNPObject::parseOptions(NPObject *obj, int *i_options,
1036                                           char*** ppsz_options)
1037 {
1038     /* WARNING: Safari does not implement NPN_HasProperty/NPN_HasMethod */
1039
1040     NPVariant value;
1041
1042     /* we are expecting to have a Javascript Array object */
1043     NPIdentifier propId = NPN_GetStringIdentifier("length");
1044     if( NPN_GetProperty(_instance, obj, propId, &value) )
1045     {
1046         int count = numberValue(value);
1047         NPN_ReleaseVariantValue(&value);
1048
1049         if( count )
1050         {
1051             long capacity = 16;
1052             char **options = (char **)malloc(capacity*sizeof(char *));
1053             if( options )
1054             {
1055                 int nOptions = 0;
1056
1057                 while( nOptions < count )
1058                 {
1059                     propId = NPN_GetIntIdentifier(nOptions);
1060                     if( ! NPN_GetProperty(_instance, obj, propId, &value) )
1061                         /* return what we got so far */
1062                         break;
1063
1064                     if( ! NPVARIANT_IS_STRING(value) )
1065                     {
1066                         /* return what we got so far */
1067                         NPN_ReleaseVariantValue(&value);
1068                         break;
1069                     }
1070
1071                     if( nOptions == capacity )
1072                     {
1073                         capacity += 16;
1074                         char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1075                         if( ! moreOptions )
1076                         {
1077                             /* failed to allocate more memory */
1078                             NPN_ReleaseVariantValue(&value);
1079                             /* return what we got so far */
1080                             *i_options = nOptions;
1081                             *ppsz_options = options;
1082                             break;
1083                         }
1084                         options = moreOptions;
1085                     }
1086
1087                     options[nOptions++] = stringValue(value);
1088                 }
1089                 *i_options = nOptions;
1090                 *ppsz_options = options;
1091             }
1092         }
1093     }
1094 }
1095
1096 /*
1097 ** implementation of libvlc subtitle object
1098 */
1099
1100 const NPUTF8 * const LibvlcSubtitleNPObject::propertyNames[] =
1101 {
1102     "track",
1103     "count",
1104 };
1105
1106 enum LibvlcSubtitleNPObjectPropertyIds
1107 {
1108     ID_subtitle_track,
1109     ID_subtitle_count,
1110 };
1111 COUNTNAMES(LibvlcSubtitleNPObject,propertyCount,propertyNames);
1112
1113 RuntimeNPObject::InvokeResult
1114 LibvlcSubtitleNPObject::getProperty(int index, NPVariant &result)
1115 {
1116     /* is plugin still running */
1117     if( isPluginRunning() )
1118     {
1119         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1120         libvlc_exception_t ex;
1121         libvlc_exception_init(&ex);
1122
1123         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1124         RETURN_ON_EXCEPTION(this,ex);
1125
1126         switch( index )
1127         {
1128             case ID_subtitle_track:
1129             {
1130                 /* get the current subtitle ID */
1131                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1132                 RETURN_ON_EXCEPTION(this,ex);
1133                 /* return it */
1134                 INT32_TO_NPVARIANT(i_spu, result);
1135                 return INVOKERESULT_NO_ERROR;
1136             }
1137             case ID_subtitle_count:
1138             {
1139                 /* get the number of subtitles available */
1140                 int i_spu = libvlc_video_get_spu_count(p_md, &ex);
1141                 RETURN_ON_EXCEPTION(this,ex);
1142                 /* return it */
1143                 INT32_TO_NPVARIANT(i_spu, result);
1144                 return INVOKERESULT_NO_ERROR;
1145             }
1146         }
1147     }
1148     return INVOKERESULT_GENERIC_ERROR;
1149 }
1150
1151 RuntimeNPObject::InvokeResult
1152 LibvlcSubtitleNPObject::setProperty(int index, const NPVariant &value)
1153 {
1154     /* is plugin still running */
1155     if( isPluginRunning() )
1156     {
1157         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1158         libvlc_exception_t ex;
1159         libvlc_exception_init(&ex);
1160
1161         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1162         RETURN_ON_EXCEPTION(this,ex);
1163
1164         switch( index )
1165         {
1166             case ID_subtitle_track:
1167             {
1168                 if( isNumberValue(value) )
1169                 {
1170                     /* set the new subtitle track to show */
1171                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1172                     RETURN_ON_EXCEPTION(this,ex);
1173
1174                     return INVOKERESULT_NO_ERROR;
1175                 }
1176                 return INVOKERESULT_INVALID_VALUE;
1177             }
1178         }
1179     }
1180     return INVOKERESULT_GENERIC_ERROR;
1181 }
1182
1183 const NPUTF8 * const LibvlcSubtitleNPObject::methodNames[] =
1184 {
1185     "description"
1186 };
1187 COUNTNAMES(LibvlcSubtitleNPObject,methodCount,methodNames);
1188
1189 enum LibvlcSubtitleNPObjectMethodIds
1190 {
1191     ID_subtitle_description
1192 };
1193
1194 RuntimeNPObject::InvokeResult
1195 LibvlcSubtitleNPObject::invoke(int index, const NPVariant *args,
1196                             uint32_t argCount, NPVariant &result)
1197 {
1198     /* is plugin still running */
1199     if( isPluginRunning() )
1200     {
1201         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1202         libvlc_exception_t ex;
1203         libvlc_exception_init(&ex);
1204
1205         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1206         RETURN_ON_EXCEPTION(this,ex);
1207
1208         switch( index )
1209         {
1210             case ID_subtitle_description:
1211             {
1212                 if( argCount == 1)
1213                 {
1214                     char *psz_name;
1215                     int i_spuID, i_limit, i;
1216                     libvlc_track_description_t *p_spuDesc;
1217
1218                     /* get subtitles description */
1219                     p_spuDesc = libvlc_video_get_spu_description(p_md, &ex);
1220                     RETURN_ON_EXCEPTION(this,ex);
1221                     if( !p_spuDesc )
1222                         return INVOKERESULT_GENERIC_ERROR;
1223
1224                     /* get the number of subtitle available */
1225                     i_limit = libvlc_video_get_spu_count(p_md, &ex);
1226                     RETURN_ON_EXCEPTION(this,ex);
1227
1228                     /* check if a number is given by the user
1229                      * and get the subtitle number */
1230                     if( isNumberValue(args[0]) )
1231                         i_spuID = numberValue(args[0]);
1232                     else
1233                         return INVOKERESULT_INVALID_VALUE;
1234
1235                     /* if bad number is given return invalid value */
1236                     if ( ( i_spuID > ( i_limit -1 ) ) || ( i_spuID < 0 ) )
1237                         return INVOKERESULT_INVALID_VALUE;
1238
1239                     /* get the good spuDesc */
1240                     for( i = 0 ; i < i_spuID ; i++ )
1241                     {
1242                         p_spuDesc = p_spuDesc->p_next;
1243                     }
1244                     psz_name = p_spuDesc->psz_name;
1245
1246                     /* return the name of the track chosen */
1247                     return invokeResultString(psz_name, result);
1248                 }
1249                 return INVOKERESULT_NO_SUCH_METHOD;
1250             }
1251             default:
1252                 return INVOKERESULT_NO_SUCH_METHOD;
1253         }
1254     }
1255     return INVOKERESULT_GENERIC_ERROR;
1256 }
1257
1258 /*
1259 ** implementation of libvlc video object
1260 */
1261
1262 const NPUTF8 * const LibvlcVideoNPObject::propertyNames[] =
1263 {
1264     "fullscreen",
1265     "height",
1266     "width",
1267     "aspectRatio",
1268     "subtitle",
1269     "crop",
1270     "teletext"
1271 };
1272
1273 enum LibvlcVideoNPObjectPropertyIds
1274 {
1275     ID_video_fullscreen,
1276     ID_video_height,
1277     ID_video_width,
1278     ID_video_aspectratio,
1279     ID_video_subtitle,
1280     ID_video_crop,
1281     ID_video_teletext
1282 };
1283 COUNTNAMES(LibvlcVideoNPObject,propertyCount,propertyNames);
1284
1285 RuntimeNPObject::InvokeResult
1286 LibvlcVideoNPObject::getProperty(int index, NPVariant &result)
1287 {
1288     /* is plugin still running */
1289     if( isPluginRunning() )
1290     {
1291         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1292         libvlc_exception_t ex;
1293         libvlc_exception_init(&ex);
1294
1295         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1296         RETURN_ON_EXCEPTION(this,ex);
1297
1298         switch( index )
1299         {
1300             case ID_video_fullscreen:
1301             {
1302                 int val = p_plugin->get_fullscreen(&ex);
1303                 RETURN_ON_EXCEPTION(this,ex);
1304                 BOOLEAN_TO_NPVARIANT(val, result);
1305                 return INVOKERESULT_NO_ERROR;
1306             }
1307             case ID_video_height:
1308             {
1309                 int val = libvlc_video_get_height(p_md, &ex);
1310                 RETURN_ON_EXCEPTION(this,ex);
1311                 INT32_TO_NPVARIANT(val, result);
1312                 return INVOKERESULT_NO_ERROR;
1313             }
1314             case ID_video_width:
1315             {
1316                 int val = libvlc_video_get_width(p_md, &ex);
1317                 RETURN_ON_EXCEPTION(this,ex);
1318                 INT32_TO_NPVARIANT(val, result);
1319                 return INVOKERESULT_NO_ERROR;
1320             }
1321             case ID_video_aspectratio:
1322             {
1323                 NPUTF8 *psz_aspect = libvlc_video_get_aspect_ratio(p_md, &ex);
1324                 RETURN_ON_EXCEPTION(this,ex);
1325                 if( !psz_aspect )
1326                     return INVOKERESULT_GENERIC_ERROR;
1327
1328                 STRINGZ_TO_NPVARIANT(psz_aspect, result);
1329                 return INVOKERESULT_NO_ERROR;
1330             }
1331             case ID_video_subtitle:
1332             {
1333                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1334                 RETURN_ON_EXCEPTION(this,ex);
1335                 INT32_TO_NPVARIANT(i_spu, result);
1336                 return INVOKERESULT_NO_ERROR;
1337             }
1338             case ID_video_crop:
1339             {
1340                 NPUTF8 *psz_geometry = libvlc_video_get_crop_geometry(p_md, &ex);
1341                 RETURN_ON_EXCEPTION(this,ex);
1342                 if( !psz_geometry )
1343                     return INVOKERESULT_GENERIC_ERROR;
1344
1345                 STRINGZ_TO_NPVARIANT(psz_geometry, result);
1346                 return INVOKERESULT_NO_ERROR;
1347             }
1348             case ID_video_teletext:
1349             {
1350                 int i_page = libvlc_video_get_teletext(p_md, &ex);
1351                 RETURN_ON_EXCEPTION(this,ex);
1352                 INT32_TO_NPVARIANT(i_page, result);
1353                 return INVOKERESULT_NO_ERROR;
1354             }
1355         }
1356     }
1357     return INVOKERESULT_GENERIC_ERROR;
1358 }
1359
1360 RuntimeNPObject::InvokeResult
1361 LibvlcVideoNPObject::setProperty(int index, const NPVariant &value)
1362 {
1363     /* is plugin still running */
1364     if( isPluginRunning() )
1365     {
1366         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1367         libvlc_exception_t ex;
1368         libvlc_exception_init(&ex);
1369
1370         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1371         RETURN_ON_EXCEPTION(this,ex);
1372
1373         switch( index )
1374         {
1375             case ID_video_fullscreen:
1376             {
1377                 if( ! NPVARIANT_IS_BOOLEAN(value) )
1378                 {
1379                     return INVOKERESULT_INVALID_VALUE;
1380                 }
1381
1382                 int val = NPVARIANT_TO_BOOLEAN(value);
1383                 p_plugin->set_fullscreen(val, &ex);
1384                 RETURN_ON_EXCEPTION(this,ex);
1385                 return INVOKERESULT_NO_ERROR;
1386             }
1387             case ID_video_aspectratio:
1388             {
1389                 char *psz_aspect = NULL;
1390
1391                 if( ! NPVARIANT_IS_STRING(value) )
1392                 {
1393                     return INVOKERESULT_INVALID_VALUE;
1394                 }
1395
1396                 psz_aspect = stringValue(NPVARIANT_TO_STRING(value));
1397                 if( !psz_aspect )
1398                 {
1399                     return INVOKERESULT_GENERIC_ERROR;
1400                 }
1401
1402                 libvlc_video_set_aspect_ratio(p_md, psz_aspect, &ex);
1403                 free(psz_aspect);
1404                 RETURN_ON_EXCEPTION(this,ex);
1405
1406                 return INVOKERESULT_NO_ERROR;
1407             }
1408             case ID_video_subtitle:
1409             {
1410                 if( isNumberValue(value) )
1411                 {
1412                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1413                     RETURN_ON_EXCEPTION(this,ex);
1414
1415                     return INVOKERESULT_NO_ERROR;
1416                 }
1417                 return INVOKERESULT_INVALID_VALUE;
1418             }
1419             case ID_video_crop:
1420             {
1421                 char *psz_geometry = NULL;
1422
1423                 if( ! NPVARIANT_IS_STRING(value) )
1424                 {
1425                     return INVOKERESULT_INVALID_VALUE;
1426                 }
1427
1428                 psz_geometry = stringValue(NPVARIANT_TO_STRING(value));
1429                 if( !psz_geometry )
1430                 {
1431                     return INVOKERESULT_GENERIC_ERROR;
1432                 }
1433
1434                 libvlc_video_set_crop_geometry(p_md, psz_geometry, &ex);
1435                 free(psz_geometry);
1436                 RETURN_ON_EXCEPTION(this,ex);
1437
1438                 return INVOKERESULT_NO_ERROR;
1439             }
1440             case ID_video_teletext:
1441             {
1442                 if( isNumberValue(value) )
1443                 {
1444                     libvlc_video_set_teletext(p_md, numberValue(value), &ex);
1445                     RETURN_ON_EXCEPTION(this,ex);
1446
1447                     return INVOKERESULT_NO_ERROR;
1448                 }
1449                 return INVOKERESULT_INVALID_VALUE;
1450             }
1451         }
1452     }
1453     return INVOKERESULT_GENERIC_ERROR;
1454 }
1455
1456 const NPUTF8 * const LibvlcVideoNPObject::methodNames[] =
1457 {
1458     "toggleFullscreen",
1459     "toggleTeletext"
1460 };
1461 COUNTNAMES(LibvlcVideoNPObject,methodCount,methodNames);
1462
1463 enum LibvlcVideoNPObjectMethodIds
1464 {
1465     ID_video_togglefullscreen,
1466     ID_video_toggleteletext
1467 };
1468
1469 RuntimeNPObject::InvokeResult
1470 LibvlcVideoNPObject::invoke(int index, const NPVariant *args,
1471                             uint32_t argCount, NPVariant &result)
1472 {
1473     /* is plugin still running */
1474     if( isPluginRunning() )
1475     {
1476         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1477         libvlc_exception_t ex;
1478         libvlc_exception_init(&ex);
1479
1480         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1481         RETURN_ON_EXCEPTION(this,ex);
1482
1483         switch( index )
1484         {
1485             case ID_video_togglefullscreen:
1486                 if( argCount == 0 )
1487                 {
1488                     p_plugin->toggle_fullscreen(&ex);
1489                     RETURN_ON_EXCEPTION(this,ex);
1490                     VOID_TO_NPVARIANT(result);
1491                     return INVOKERESULT_NO_ERROR;
1492                 }
1493                 return INVOKERESULT_NO_SUCH_METHOD;
1494             case ID_video_toggleteletext:
1495                 if( argCount == 0 )
1496                 {
1497                     libvlc_toggle_teletext(p_md, &ex);
1498                     RETURN_ON_EXCEPTION(this,ex);
1499                     VOID_TO_NPVARIANT(result);
1500                     return INVOKERESULT_NO_ERROR;
1501                 }
1502                 return INVOKERESULT_NO_SUCH_METHOD;
1503             default:
1504                 return INVOKERESULT_NO_SUCH_METHOD;
1505         }
1506     }
1507     return INVOKERESULT_GENERIC_ERROR;
1508 }