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