blob: 0b777412960adacd0ec223532b31d5fa29658009 [file] [log] [blame]
Grace Klobafbe47c02009-05-14 17:31:45 -07001/*
2 * Copyright 2008, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <stdlib.h>
27#include <string.h>
28#include <stdio.h>
29#include "main.h"
30#include "PluginObject.h"
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -040031#include "AnimationPlugin.h"
32#include "BackgroundPlugin.h"
Grace Klobafbe47c02009-05-14 17:31:45 -070033#include "android_npapi.h"
34
35NPNetscapeFuncs* browser;
36#define EXPORT __attribute__((visibility("default")))
37
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040038NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
Grace Klobafbe47c02009-05-14 17:31:45 -070039 char* argn[], char* argv[], NPSavedData* saved);
40NPError NPP_Destroy(NPP instance, NPSavedData** save);
41NPError NPP_SetWindow(NPP instance, NPWindow* window);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040042NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
Grace Klobafbe47c02009-05-14 17:31:45 -070043 NPBool seekable, uint16* stype);
44NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
45int32 NPP_WriteReady(NPP instance, NPStream* stream);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040046int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len,
Grace Klobafbe47c02009-05-14 17:31:45 -070047 void* buffer);
48void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
49void NPP_Print(NPP instance, NPPrint* platformPrint);
50int16 NPP_HandleEvent(NPP instance, void* event);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040051void NPP_URLNotify(NPP instance, const char* URL, NPReason reason,
Grace Klobafbe47c02009-05-14 17:31:45 -070052 void* notifyData);
53NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
54NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value);
55
56extern "C" {
57EXPORT NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context);
58EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value);
59EXPORT const char* NP_GetMIMEDescription(void);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040060EXPORT void NP_Shutdown(void);
Grace Klobafbe47c02009-05-14 17:31:45 -070061};
62
63ANPAudioTrackInterfaceV0 gSoundI;
Mike Reed224adad2009-06-10 10:24:01 -040064ANPBitmapInterfaceV0 gBitmapI;
Grace Klobafbe47c02009-05-14 17:31:45 -070065ANPCanvasInterfaceV0 gCanvasI;
66ANPLogInterfaceV0 gLogI;
67ANPPaintInterfaceV0 gPaintI;
68ANPPathInterfaceV0 gPathI;
69ANPTypefaceInterfaceV0 gTypefaceI;
Derek Sollenberger5b011e32009-06-22 11:39:40 -040070ANPWindowInterfaceV0 gWindowI;
Grace Klobafbe47c02009-05-14 17:31:45 -070071
72#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
Derek Sollenberger5b011e32009-06-22 11:39:40 -040073#define DEBUG_PLUGIN_EVENTS 0
Grace Klobafbe47c02009-05-14 17:31:45 -070074
75NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context)
76{
77 // Make sure we have a function table equal or larger than we are built against.
78 if (browserFuncs->size < sizeof(NPNetscapeFuncs)) {
79 return NPERR_GENERIC_ERROR;
80 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040081
Grace Klobafbe47c02009-05-14 17:31:45 -070082 // Copy the function table (structure)
83 browser = (NPNetscapeFuncs*) malloc(sizeof(NPNetscapeFuncs));
84 memcpy(browser, browserFuncs, sizeof(NPNetscapeFuncs));
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040085
Grace Klobafbe47c02009-05-14 17:31:45 -070086 // Build the plugin function table
87 pluginFuncs->version = 11;
88 pluginFuncs->size = sizeof(pluginFuncs);
89 pluginFuncs->newp = NPP_New;
90 pluginFuncs->destroy = NPP_Destroy;
91 pluginFuncs->setwindow = NPP_SetWindow;
92 pluginFuncs->newstream = NPP_NewStream;
93 pluginFuncs->destroystream = NPP_DestroyStream;
94 pluginFuncs->asfile = NPP_StreamAsFile;
95 pluginFuncs->writeready = NPP_WriteReady;
96 pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
97 pluginFuncs->print = NPP_Print;
98 pluginFuncs->event = NPP_HandleEvent;
99 pluginFuncs->urlnotify = NPP_URLNotify;
100 pluginFuncs->getvalue = NPP_GetValue;
101 pluginFuncs->setvalue = NPP_SetValue;
102
103 static const struct {
104 NPNVariable v;
105 uint32_t size;
106 ANPInterface* i;
107 } gPairs[] = {
Mike Reed224adad2009-06-10 10:24:01 -0400108 { kBitmapInterfaceV0_ANPGetValue, sizeof(gBitmapI), &gBitmapI },
Grace Klobafbe47c02009-05-14 17:31:45 -0700109 { kCanvasInterfaceV0_ANPGetValue, sizeof(gCanvasI), &gCanvasI },
Mike Reed224adad2009-06-10 10:24:01 -0400110 { kLogInterfaceV0_ANPGetValue, sizeof(gLogI), &gLogI },
Grace Klobafbe47c02009-05-14 17:31:45 -0700111 { kPaintInterfaceV0_ANPGetValue, sizeof(gPaintI), &gPaintI },
112 { kPathInterfaceV0_ANPGetValue, sizeof(gPathI), &gPathI },
113 { kTypefaceInterfaceV0_ANPGetValue, sizeof(gPaintI), &gTypefaceI },
114 { kAudioTrackInterfaceV0_ANPGetValue, sizeof(gSoundI), &gSoundI },
Derek Sollenberger5b011e32009-06-22 11:39:40 -0400115 { kWindowInterfaceV0_ANPGetValue, sizeof(gWindowI), &gWindowI },
Grace Klobafbe47c02009-05-14 17:31:45 -0700116 };
117 for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) {
118 gPairs[i].i->inSize = gPairs[i].size;
119 NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i);
120 if (err) {
121 return err;
122 }
123 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400124
Grace Klobafbe47c02009-05-14 17:31:45 -0700125 return NPERR_NO_ERROR;
126}
127
128void NP_Shutdown(void)
129{
130
131}
132
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400133const char *NP_GetMIMEDescription(void)
Grace Klobafbe47c02009-05-14 17:31:45 -0700134{
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400135 return "application/x-testbrowserplugin:tst:Test plugin mimetype is application/x-testbrowserplugin";
Grace Klobafbe47c02009-05-14 17:31:45 -0700136}
137
138NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
139 char* argn[], char* argv[], NPSavedData* saved)
140{
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400141
142 /* BEGIN: STANDARD PLUGIN FRAMEWORK */
Grace Klobafbe47c02009-05-14 17:31:45 -0700143 PluginObject *obj = NULL;
144
145 // Scripting functions appeared in NPAPI version 14
146 if (browser->version >= 14) {
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400147 instance->pdata = browser->createobject (instance, getPluginClass());
148 obj = static_cast<PluginObject*>(instance->pdata);
149 bzero(obj, sizeof(*obj));
Grace Klobafbe47c02009-05-14 17:31:45 -0700150 }
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400151 /* END: STANDARD PLUGIN FRAMEWORK */
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400152
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400153 // select the drawing model based on user input
Grace Klobafbe47c02009-05-14 17:31:45 -0700154 ANPDrawingModel model = kBitmap_ANPDrawingModel;
155
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400156 for (int i = 0; i < argc; i++) {
Grace Klobafbe47c02009-05-14 17:31:45 -0700157 if (!strcmp(argn[i], "DrawingModel")) {
158 if (!strcmp(argv[i], "Bitmap")) {
159 model = kBitmap_ANPDrawingModel;
160 }
161 if (!strcmp(argv[i], "Canvas")) {
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400162 //TODO support drawing on canvas instead of bitmap
Grace Klobafbe47c02009-05-14 17:31:45 -0700163 }
164 gLogI.log(instance, kDebug_ANPLogType, "------ %p DrawingModel is %d", instance, model);
165 break;
166 }
167 }
168
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400169 // comment this out to use the default model (bitmaps)
170 NPError err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue,
Grace Klobafbe47c02009-05-14 17:31:45 -0700171 reinterpret_cast<void*>(model));
172 if (err) {
173 gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err);
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400174 return err;
Grace Klobafbe47c02009-05-14 17:31:45 -0700175 }
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400176
177 // select the pluginType
178 for (int i = 0; i < argc; i++) {
179 if (!strcmp(argn[i], "PluginType")) {
180 if (!strcmp(argv[i], "Animation")) {
181 obj->pluginType = kAnimation_PluginType;
182 obj->activePlugin = new BallAnimation(instance);
183 }
184 else if (!strcmp(argv[i], "Audio")) {
185 obj->pluginType = kAudio_PluginType;
186 //TODO add audio here
187 }
188 else if (!strcmp(argv[i], "Background")) {
189 obj->pluginType = kBackground_PluginType;
190 obj->activePlugin = new BackgroundPlugin(instance);
191 }
192 gLogI.log(instance, kDebug_ANPLogType, "------ %p PluginType is %d", instance, obj->pluginType);
193 break;
194 }
195 }
196
197 // if no pluginType is specified then default to Animation
198 if (!obj->pluginType) {
199 obj->pluginType = kAnimation_PluginType;
200 obj->activePlugin = new BallAnimation(instance);
201 }
202
203 return NPERR_NO_ERROR;
Grace Klobafbe47c02009-05-14 17:31:45 -0700204}
205
206NPError NPP_Destroy(NPP instance, NPSavedData** save)
207{
208 PluginObject *obj = (PluginObject*) instance->pdata;
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400209 delete obj->activePlugin;
Grace Klobafbe47c02009-05-14 17:31:45 -0700210 gSoundI.deleteTrack(obj->track);
211
212 return NPERR_NO_ERROR;
213}
214
Grace Klobafbe47c02009-05-14 17:31:45 -0700215NPError NPP_SetWindow(NPP instance, NPWindow* window)
216{
217 PluginObject *obj = (PluginObject*) instance->pdata;
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400218
Grace Klobafbe47c02009-05-14 17:31:45 -0700219 // Do nothing if browser didn't support NPN_CreateObject which would have created the PluginObject.
220 if (obj != NULL) {
221 obj->window = window;
222 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400223
Grace Klobafbe47c02009-05-14 17:31:45 -0700224 browser->invalidaterect(instance, NULL);
225
226 return NPERR_NO_ERROR;
227}
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400228
Grace Klobafbe47c02009-05-14 17:31:45 -0700229NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
230{
231 *stype = NP_ASFILEONLY;
232 return NPERR_NO_ERROR;
233}
234
235NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
236{
237 return NPERR_NO_ERROR;
238}
239
240int32 NPP_WriteReady(NPP instance, NPStream* stream)
241{
242 return 0;
243}
244
245int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
246{
247 return 0;
248}
249
250void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
251{
252}
253
254void NPP_Print(NPP instance, NPPrint* platformPrint)
255{
Grace Klobafbe47c02009-05-14 17:31:45 -0700256}
257
258struct SoundPlay {
259 NPP instance;
260 ANPAudioTrack* track;
261 FILE* file;
262};
263
264static void audioCallback(ANPAudioEvent evt, void* user, ANPAudioBuffer* buffer) {
265 switch (evt) {
266 case kMoreData_ANPAudioEvent: {
267 SoundPlay* play = reinterpret_cast<SoundPlay*>(user);
268 size_t amount = fread(buffer->bufferData, 1, buffer->size, play->file);
269 buffer->size = amount;
270 if (amount == 0) {
271 gSoundI.stop(play->track);
272 fclose(play->file);
273 play->file = NULL;
274 // need to notify our main thread to delete the track now
275 }
276 break;
277 }
278 default:
279 break;
280 }
281}
282
283static ANPAudioTrack* createTrack(NPP instance, const char path[]) {
284 FILE* f = fopen(path, "r");
285 gLogI.log(instance, kWarning_ANPLogType, "--- path %s FILE %p", path, f);
286 if (NULL == f) {
287 return NULL;
288 }
289 SoundPlay* play = new SoundPlay;
290 play->file = f;
291 play->track = gSoundI.newTrack(44100, kPCM16Bit_ANPSampleFormat, 2, audioCallback, play);
292 if (NULL == play->track) {
293 fclose(f);
294 delete play;
295 return NULL;
296 }
297 return play->track;
298}
299
300int16 NPP_HandleEvent(NPP instance, void* event)
301{
302 PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata);
303 const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event);
304
Derek Sollenberger5b011e32009-06-22 11:39:40 -0400305#if DEBUG_PLUGIN_EVENTS
Grace Klobafbe47c02009-05-14 17:31:45 -0700306 switch (evt->eventType) {
307 case kDraw_ANPEventType:
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400308
309 if (evt->data.draw.model == kBitmap_ANPDrawingModel) {
310
311 static ANPBitmapFormat currentFormat = -1;
312 if (evt->data.draw.data.bitmap.format != currentFormat) {
313 currentFormat = evt->data.draw.data.bitmap.format;
314 gLogI.log(instance, kDebug_ANPLogType, "---- %p Draw (bitmap)"
315 " clip=%d,%d,%d,%d format=%d", instance,
316 evt->data.draw.clip.left,
317 evt->data.draw.clip.top,
318 evt->data.draw.clip.right,
319 evt->data.draw.clip.bottom,
320 evt->data.draw.data.bitmap.format);
321 }
Grace Klobafbe47c02009-05-14 17:31:45 -0700322 }
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400323 break;
Grace Klobafbe47c02009-05-14 17:31:45 -0700324
325 case kKey_ANPEventType:
326 gLogI.log(instance, kDebug_ANPLogType, "---- %p Key action=%d"
327 " code=%d vcode=%d unichar=%d repeat=%d mods=%x", instance,
328 evt->data.key.action,
329 evt->data.key.nativeCode,
330 evt->data.key.virtualCode,
331 evt->data.key.unichar,
332 evt->data.key.repeatCount,
333 evt->data.key.modifiers);
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400334 break;
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400335
336 case kLifecycle_ANPEventType:
337 gLogI.log(instance, kDebug_ANPLogType, "---- %p Lifecycle action=%d",
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400338 instance, evt->data.lifecycle.action);
Mike Reed1e7c3312009-05-26 16:37:45 -0400339 break;
Grace Klobafbe47c02009-05-14 17:31:45 -0700340
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400341 case kTouch_ANPEventType:
Grace Klobafbe47c02009-05-14 17:31:45 -0700342 gLogI.log(instance, kDebug_ANPLogType, "---- %p Touch action=%d [%d %d]",
343 instance, evt->data.touch.action, evt->data.touch.x,
344 evt->data.touch.y);
345 if (kUp_ANPTouchAction == evt->data.touch.action) {
346 if (NULL == obj->track) {
347 obj->track = createTrack(instance, "/sdcard/sample.snd");
348 }
349 if (obj->track) {
350 gLogI.log(instance, kDebug_ANPLogType, "track %p %d",
351 obj->track, gSoundI.isStopped(obj->track));
352 if (gSoundI.isStopped(obj->track)) {
353 gSoundI.start(obj->track);
354 } else {
355 gSoundI.pause(obj->track);
356 }
357 }
358 }
Derek Sollenberger5b011e32009-06-22 11:39:40 -0400359 break;
360
361 case kVisibleRect_ANPEventType:
362 gLogI.log(instance, kDebug_ANPLogType, "---- %p VisibleRect [%d %d %d %d]",
363 instance, evt->data.visibleRect.x, evt->data.visibleRect.y,
364 evt->data.visibleRect.width, evt->data.visibleRect.height);
365 break;
Grace Klobafbe47c02009-05-14 17:31:45 -0700366
367 default:
Derek Sollenberger5b011e32009-06-22 11:39:40 -0400368 gLogI.log(instance, kError_ANPLogType, "---- %p Unknown Event [%d]",
369 instance, evt->eventType);
Grace Klobafbe47c02009-05-14 17:31:45 -0700370 break;
371 }
Derek Sollenberger5b011e32009-06-22 11:39:40 -0400372#endif
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400373
374 if(!obj->activePlugin) {
375 gLogI.log(instance, kError_ANPLogType, "the active plugin is null.");
376 return 0; // unknown or unhandled event
377 }
378 else {
379 return obj->activePlugin->handleEvent(evt);
380 }
Grace Klobafbe47c02009-05-14 17:31:45 -0700381}
382
383void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
384{
385
386}
387
388EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) {
389
390 if (variable == NPPVpluginNameString) {
391 const char **str = (const char **)value;
392 *str = "Test Plugin";
393 return NPERR_NO_ERROR;
394 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400395
Grace Klobafbe47c02009-05-14 17:31:45 -0700396 if (variable == NPPVpluginDescriptionString) {
397 const char **str = (const char **)value;
398 *str = "Description of Test Plugin";
399 return NPERR_NO_ERROR;
400 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400401
Grace Klobafbe47c02009-05-14 17:31:45 -0700402 return NPERR_GENERIC_ERROR;
403}
404
405NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
406{
407 if (variable == NPPVpluginScriptableNPObject) {
408 void **v = (void **)value;
409 PluginObject *obj = (PluginObject*) instance->pdata;
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400410
Grace Klobafbe47c02009-05-14 17:31:45 -0700411 if (obj)
412 browser->retainobject((NPObject*)obj);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400413
Grace Klobafbe47c02009-05-14 17:31:45 -0700414 *v = obj;
415 return NPERR_NO_ERROR;
416 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400417
Grace Klobafbe47c02009-05-14 17:31:45 -0700418 return NPERR_GENERIC_ERROR;
419}
420
421NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
422{
423 return NPERR_GENERIC_ERROR;
424}
425