blob: ab95ce618e7f009e18e6b30cb0b506f1c5904c74 [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"
31#include "pluginGraphics.h"
32#include "android_npapi.h"
33
34NPNetscapeFuncs* browser;
35#define EXPORT __attribute__((visibility("default")))
36
37NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
38 char* argn[], char* argv[], NPSavedData* saved);
39NPError NPP_Destroy(NPP instance, NPSavedData** save);
40NPError NPP_SetWindow(NPP instance, NPWindow* window);
41NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
42 NPBool seekable, uint16* stype);
43NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
44int32 NPP_WriteReady(NPP instance, NPStream* stream);
45int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len,
46 void* buffer);
47void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
48void NPP_Print(NPP instance, NPPrint* platformPrint);
49int16 NPP_HandleEvent(NPP instance, void* event);
50void NPP_URLNotify(NPP instance, const char* URL, NPReason reason,
51 void* notifyData);
52NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
53NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value);
54
55extern "C" {
56EXPORT NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context);
57EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value);
58EXPORT const char* NP_GetMIMEDescription(void);
59EXPORT void NP_Shutdown(void);
60};
61
62ANPAudioTrackInterfaceV0 gSoundI;
63ANPCanvasInterfaceV0 gCanvasI;
64ANPLogInterfaceV0 gLogI;
65ANPPaintInterfaceV0 gPaintI;
66ANPPathInterfaceV0 gPathI;
67ANPTypefaceInterfaceV0 gTypefaceI;
68
69#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
70
71NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context)
72{
73 // Make sure we have a function table equal or larger than we are built against.
74 if (browserFuncs->size < sizeof(NPNetscapeFuncs)) {
75 return NPERR_GENERIC_ERROR;
76 }
77
78 // Copy the function table (structure)
79 browser = (NPNetscapeFuncs*) malloc(sizeof(NPNetscapeFuncs));
80 memcpy(browser, browserFuncs, sizeof(NPNetscapeFuncs));
81
82 // Build the plugin function table
83 pluginFuncs->version = 11;
84 pluginFuncs->size = sizeof(pluginFuncs);
85 pluginFuncs->newp = NPP_New;
86 pluginFuncs->destroy = NPP_Destroy;
87 pluginFuncs->setwindow = NPP_SetWindow;
88 pluginFuncs->newstream = NPP_NewStream;
89 pluginFuncs->destroystream = NPP_DestroyStream;
90 pluginFuncs->asfile = NPP_StreamAsFile;
91 pluginFuncs->writeready = NPP_WriteReady;
92 pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
93 pluginFuncs->print = NPP_Print;
94 pluginFuncs->event = NPP_HandleEvent;
95 pluginFuncs->urlnotify = NPP_URLNotify;
96 pluginFuncs->getvalue = NPP_GetValue;
97 pluginFuncs->setvalue = NPP_SetValue;
98
99 static const struct {
100 NPNVariable v;
101 uint32_t size;
102 ANPInterface* i;
103 } gPairs[] = {
104 { kLogInterfaceV0_ANPGetValue, sizeof(gLogI), &gLogI },
105 { kCanvasInterfaceV0_ANPGetValue, sizeof(gCanvasI), &gCanvasI },
106 { kPaintInterfaceV0_ANPGetValue, sizeof(gPaintI), &gPaintI },
107 { kPathInterfaceV0_ANPGetValue, sizeof(gPathI), &gPathI },
108 { kTypefaceInterfaceV0_ANPGetValue, sizeof(gPaintI), &gTypefaceI },
109 { kAudioTrackInterfaceV0_ANPGetValue, sizeof(gSoundI), &gSoundI },
110 };
111 for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) {
112 gPairs[i].i->inSize = gPairs[i].size;
113 NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i);
114 if (err) {
115 return err;
116 }
117 }
118
119 return NPERR_NO_ERROR;
120}
121
122void NP_Shutdown(void)
123{
124
125}
126
127const char *NP_GetMIMEDescription(void)
128{
129 return "application/x-testplugin:tst:Test plugin mimetype is application/x-testplugin";
130}
131
132NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
133 char* argn[], char* argv[], NPSavedData* saved)
134{
135 PluginObject *obj = NULL;
136
137 // Scripting functions appeared in NPAPI version 14
138 if (browser->version >= 14) {
139 instance->pdata = browser->createobject (instance, getPluginClass());
140 obj = static_cast<PluginObject*>(instance->pdata);
141 bzero(obj, sizeof(*obj));
142 }
143
144 uint32_t bits;
145 NPError err = browser->getvalue(instance, kSupportedDrawingModel_ANPGetValue, &bits);
146 if (err) {
147 gLogI.log(instance, kError_ANPLogType, "supported model err %d", err);
148 return err;
149 }
150
151 ANPDrawingModel model = kBitmap_ANPDrawingModel;
152
153 int count = argc;
154 for (int i = 0; i < count; i++) {
155 if (!strcmp(argn[i], "DrawingModel")) {
156 if (!strcmp(argv[i], "Bitmap")) {
157 model = kBitmap_ANPDrawingModel;
158 }
159 if (!strcmp(argv[i], "Canvas")) {
160 // obj->mTestTimers = true;
161 }
162 gLogI.log(instance, kDebug_ANPLogType, "------ %p DrawingModel is %d", instance, model);
163 break;
164 }
165 }
166
167 // comment this out to draw via bitmaps (the default)
168 err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue,
169 reinterpret_cast<void*>(model));
170 if (err) {
171 gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err);
172 }
173 return err;
174}
175
176NPError NPP_Destroy(NPP instance, NPSavedData** save)
177{
178 PluginObject *obj = (PluginObject*) instance->pdata;
179 delete obj->anim;
180 gSoundI.deleteTrack(obj->track);
181
182 return NPERR_NO_ERROR;
183}
184
185static void timer_oneshot(NPP instance, uint32 timerID) {
186 gLogI.log(instance, kDebug_ANPLogType, "-------- oneshot timer\n");
187}
188
189static int gTimerRepeatCount;
190static void timer_repeat(NPP instance, uint32 timerID) {
191
192 gLogI.log(instance, kDebug_ANPLogType, "-------- repeat timer %d\n",
193 gTimerRepeatCount);
194 if (--gTimerRepeatCount == 0) {
195 browser->unscheduletimer(instance, timerID);
196 }
197}
198
199static void timer_neverfires(NPP instance, uint32 timerID) {
200 gLogI.log(instance, kError_ANPLogType, "-------- timer_neverfires!!!\n");
201}
202
203#define TIMER_INTERVAL 50
204
205static void timer_latency(NPP instance, uint32 timerID) {
206 PluginObject *obj = (PluginObject*) instance->pdata;
207
208 obj->mTimerCount += 1;
209
210 uint32_t now = getMSecs();
211 uint32_t interval = now - obj->mPrevTime;
212
213 uint32_t dur = now - obj->mStartTime;
214 uint32_t expectedDur = obj->mTimerCount * TIMER_INTERVAL;
215 int32_t drift = dur - expectedDur;
216 int32_t aveDrift = drift / obj->mTimerCount;
217
218 obj->mPrevTime = now;
219
220 gLogI.log(instance, kDebug_ANPLogType,
221 "-------- latency test: [%3d] interval %d expected %d, total %d expected %d, drift %d ave %d\n",
222 obj->mTimerCount, interval, TIMER_INTERVAL, dur, expectedDur,
223 drift, aveDrift);
224}
225
226NPError NPP_SetWindow(NPP instance, NPWindow* window)
227{
228 PluginObject *obj = (PluginObject*) instance->pdata;
229
230 // Do nothing if browser didn't support NPN_CreateObject which would have created the PluginObject.
231 if (obj != NULL) {
232 obj->window = window;
233 }
234
235 static bool gTestTimers;
236 if (!gTestTimers) {
237 gTestTimers = true;
238 // test for bogus timerID
239 browser->unscheduletimer(instance, 999999);
240 // test oneshot
241 browser->scheduletimer(instance, 100, false, timer_oneshot);
242 // test repeat
243 gTimerRepeatCount = 10;
244 browser->scheduletimer(instance, 50, true, timer_repeat);
245 // test unschedule immediately
246 uint32 id = browser->scheduletimer(instance, 100, false, timer_neverfires);
247 browser->unscheduletimer(instance, id);
248 // test double unschedlue (should be no-op)
249 browser->unscheduletimer(instance, id);
250 }
251
252 if (obj->mTestTimers) {
253 browser->scheduletimer(instance, TIMER_INTERVAL, true, timer_latency);
254 obj->mStartTime = obj->mPrevTime = getMSecs();
255 obj->mTestTimers = false;
256 }
257
258 browser->invalidaterect(instance, NULL);
259
260 return NPERR_NO_ERROR;
261}
262
263
264NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
265{
266 *stype = NP_ASFILEONLY;
267 return NPERR_NO_ERROR;
268}
269
270NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
271{
272 return NPERR_NO_ERROR;
273}
274
275int32 NPP_WriteReady(NPP instance, NPStream* stream)
276{
277 return 0;
278}
279
280int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
281{
282 return 0;
283}
284
285void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
286{
287}
288
289void NPP_Print(NPP instance, NPPrint* platformPrint)
290{
291
292}
293
294struct SoundPlay {
295 NPP instance;
296 ANPAudioTrack* track;
297 FILE* file;
298};
299
300static void audioCallback(ANPAudioEvent evt, void* user, ANPAudioBuffer* buffer) {
301 switch (evt) {
302 case kMoreData_ANPAudioEvent: {
303 SoundPlay* play = reinterpret_cast<SoundPlay*>(user);
304 size_t amount = fread(buffer->bufferData, 1, buffer->size, play->file);
305 buffer->size = amount;
306 if (amount == 0) {
307 gSoundI.stop(play->track);
308 fclose(play->file);
309 play->file = NULL;
310 // need to notify our main thread to delete the track now
311 }
312 break;
313 }
314 default:
315 break;
316 }
317}
318
319static ANPAudioTrack* createTrack(NPP instance, const char path[]) {
320 FILE* f = fopen(path, "r");
321 gLogI.log(instance, kWarning_ANPLogType, "--- path %s FILE %p", path, f);
322 if (NULL == f) {
323 return NULL;
324 }
325 SoundPlay* play = new SoundPlay;
326 play->file = f;
327 play->track = gSoundI.newTrack(44100, kPCM16Bit_ANPSampleFormat, 2, audioCallback, play);
328 if (NULL == play->track) {
329 fclose(f);
330 delete play;
331 return NULL;
332 }
333 return play->track;
334}
335
336int16 NPP_HandleEvent(NPP instance, void* event)
337{
338 PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata);
339 const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event);
340
341 switch (evt->eventType) {
342 case kDraw_ANPEventType:
343 switch (evt->data.drawContext.model) {
344 case kBitmap_ANPDrawingModel:
345 drawPlugin(instance, evt->data.drawContext.data.bitmap,
346 evt->data.drawContext.clip);
347 return 1;
348 default:
349 break; // unknown drawing model
350 }
351
352 case kKey_ANPEventType:
353 gLogI.log(instance, kDebug_ANPLogType, "---- %p Key action=%d"
354 " code=%d vcode=%d unichar=%d repeat=%d mods=%x", instance,
355 evt->data.key.action,
356 evt->data.key.nativeCode,
357 evt->data.key.virtualCode,
358 evt->data.key.unichar,
359 evt->data.key.repeatCount,
360 evt->data.key.modifiers);
361 if (evt->data.key.action == kDown_ANPKeyAction) {
362 obj->mUnichar = evt->data.key.unichar;
363 browser->invalidaterect(instance, NULL);
364 }
365 return 1;
Mike Reed1e7c3312009-05-26 16:37:45 -0400366
367 case kPause_ANPEventType:
368 gLogI.log(instance, kDebug_ANPLogType, "---- %p pause event\n",
369 instance);
370 break;
Grace Klobafbe47c02009-05-14 17:31:45 -0700371
Mike Reed1e7c3312009-05-26 16:37:45 -0400372 case kResume_ANPEventType:
373 gLogI.log(instance, kDebug_ANPLogType, "---- %p resume event\n",
374 instance);
375 break;
376
377 case kTouch_ANPEventType:
Grace Klobafbe47c02009-05-14 17:31:45 -0700378 gLogI.log(instance, kDebug_ANPLogType, "---- %p Touch action=%d [%d %d]",
379 instance, evt->data.touch.action, evt->data.touch.x,
380 evt->data.touch.y);
381 if (kUp_ANPTouchAction == evt->data.touch.action) {
382 if (NULL == obj->track) {
383 obj->track = createTrack(instance, "/sdcard/sample.snd");
384 }
385 if (obj->track) {
386 gLogI.log(instance, kDebug_ANPLogType, "track %p %d",
387 obj->track, gSoundI.isStopped(obj->track));
388 if (gSoundI.isStopped(obj->track)) {
389 gSoundI.start(obj->track);
390 } else {
391 gSoundI.pause(obj->track);
392 }
393 }
394 }
395 return 1;
396
397 default:
398 break;
399 }
400 return 0; // unknown or unhandled event
401}
402
403void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
404{
405
406}
407
408EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) {
409
410 if (variable == NPPVpluginNameString) {
411 const char **str = (const char **)value;
412 *str = "Test Plugin";
413 return NPERR_NO_ERROR;
414 }
415
416 if (variable == NPPVpluginDescriptionString) {
417 const char **str = (const char **)value;
418 *str = "Description of Test Plugin";
419 return NPERR_NO_ERROR;
420 }
421
422 return NPERR_GENERIC_ERROR;
423}
424
425NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
426{
427 if (variable == NPPVpluginScriptableNPObject) {
428 void **v = (void **)value;
429 PluginObject *obj = (PluginObject*) instance->pdata;
430
431 if (obj)
432 browser->retainobject((NPObject*)obj);
433
434 *v = obj;
435 return NPERR_NO_ERROR;
436 }
437
438 return NPERR_GENERIC_ERROR;
439}
440
441NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
442{
443 return NPERR_GENERIC_ERROR;
444}
445