blob: 82d29b614d9a75144735f15ef2760ac1da9ce519 [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
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040037NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
Grace Klobafbe47c02009-05-14 17:31:45 -070038 char* argn[], char* argv[], NPSavedData* saved);
39NPError NPP_Destroy(NPP instance, NPSavedData** save);
40NPError NPP_SetWindow(NPP instance, NPWindow* window);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040041NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
Grace Klobafbe47c02009-05-14 17:31:45 -070042 NPBool seekable, uint16* stype);
43NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
44int32 NPP_WriteReady(NPP instance, NPStream* stream);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040045int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len,
Grace Klobafbe47c02009-05-14 17:31:45 -070046 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);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040050void NPP_URLNotify(NPP instance, const char* URL, NPReason reason,
Grace Klobafbe47c02009-05-14 17:31:45 -070051 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);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040059EXPORT void NP_Shutdown(void);
Grace Klobafbe47c02009-05-14 17:31:45 -070060};
61
62ANPAudioTrackInterfaceV0 gSoundI;
Mike Reed224adad2009-06-10 10:24:01 -040063ANPBitmapInterfaceV0 gBitmapI;
Grace Klobafbe47c02009-05-14 17:31:45 -070064ANPCanvasInterfaceV0 gCanvasI;
65ANPLogInterfaceV0 gLogI;
66ANPPaintInterfaceV0 gPaintI;
67ANPPathInterfaceV0 gPathI;
68ANPTypefaceInterfaceV0 gTypefaceI;
69
70#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
71
72NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context)
73{
74 // Make sure we have a function table equal or larger than we are built against.
75 if (browserFuncs->size < sizeof(NPNetscapeFuncs)) {
76 return NPERR_GENERIC_ERROR;
77 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040078
Grace Klobafbe47c02009-05-14 17:31:45 -070079 // Copy the function table (structure)
80 browser = (NPNetscapeFuncs*) malloc(sizeof(NPNetscapeFuncs));
81 memcpy(browser, browserFuncs, sizeof(NPNetscapeFuncs));
Derek Sollenberger9119e7d2009-06-08 10:53:09 -040082
Grace Klobafbe47c02009-05-14 17:31:45 -070083 // Build the plugin function table
84 pluginFuncs->version = 11;
85 pluginFuncs->size = sizeof(pluginFuncs);
86 pluginFuncs->newp = NPP_New;
87 pluginFuncs->destroy = NPP_Destroy;
88 pluginFuncs->setwindow = NPP_SetWindow;
89 pluginFuncs->newstream = NPP_NewStream;
90 pluginFuncs->destroystream = NPP_DestroyStream;
91 pluginFuncs->asfile = NPP_StreamAsFile;
92 pluginFuncs->writeready = NPP_WriteReady;
93 pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
94 pluginFuncs->print = NPP_Print;
95 pluginFuncs->event = NPP_HandleEvent;
96 pluginFuncs->urlnotify = NPP_URLNotify;
97 pluginFuncs->getvalue = NPP_GetValue;
98 pluginFuncs->setvalue = NPP_SetValue;
99
100 static const struct {
101 NPNVariable v;
102 uint32_t size;
103 ANPInterface* i;
104 } gPairs[] = {
Mike Reed224adad2009-06-10 10:24:01 -0400105 { kBitmapInterfaceV0_ANPGetValue, sizeof(gBitmapI), &gBitmapI },
Grace Klobafbe47c02009-05-14 17:31:45 -0700106 { kCanvasInterfaceV0_ANPGetValue, sizeof(gCanvasI), &gCanvasI },
Mike Reed224adad2009-06-10 10:24:01 -0400107 { kLogInterfaceV0_ANPGetValue, sizeof(gLogI), &gLogI },
Grace Klobafbe47c02009-05-14 17:31:45 -0700108 { kPaintInterfaceV0_ANPGetValue, sizeof(gPaintI), &gPaintI },
109 { kPathInterfaceV0_ANPGetValue, sizeof(gPathI), &gPathI },
110 { kTypefaceInterfaceV0_ANPGetValue, sizeof(gPaintI), &gTypefaceI },
111 { kAudioTrackInterfaceV0_ANPGetValue, sizeof(gSoundI), &gSoundI },
112 };
113 for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) {
114 gPairs[i].i->inSize = gPairs[i].size;
115 NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i);
116 if (err) {
117 return err;
118 }
119 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400120
Grace Klobafbe47c02009-05-14 17:31:45 -0700121 return NPERR_NO_ERROR;
122}
123
124void NP_Shutdown(void)
125{
126
127}
128
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400129const char *NP_GetMIMEDescription(void)
Grace Klobafbe47c02009-05-14 17:31:45 -0700130{
131 return "application/x-testplugin:tst:Test plugin mimetype is application/x-testplugin";
132}
133
134NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
135 char* argn[], char* argv[], NPSavedData* saved)
136{
137 PluginObject *obj = NULL;
138
139 // Scripting functions appeared in NPAPI version 14
140 if (browser->version >= 14) {
141 instance->pdata = browser->createobject (instance, getPluginClass());
142 obj = static_cast<PluginObject*>(instance->pdata);
143 bzero(obj, sizeof(*obj));
144 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400145
Grace Klobafbe47c02009-05-14 17:31:45 -0700146 uint32_t bits;
147 NPError err = browser->getvalue(instance, kSupportedDrawingModel_ANPGetValue, &bits);
148 if (err) {
149 gLogI.log(instance, kError_ANPLogType, "supported model err %d", err);
150 return err;
151 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400152
Grace Klobafbe47c02009-05-14 17:31:45 -0700153 ANPDrawingModel model = kBitmap_ANPDrawingModel;
154
155 int count = argc;
156 for (int i = 0; i < count; i++) {
157 if (!strcmp(argn[i], "DrawingModel")) {
158 if (!strcmp(argv[i], "Bitmap")) {
159 model = kBitmap_ANPDrawingModel;
160 }
161 if (!strcmp(argv[i], "Canvas")) {
162 // obj->mTestTimers = true;
163 }
164 gLogI.log(instance, kDebug_ANPLogType, "------ %p DrawingModel is %d", instance, model);
165 break;
166 }
167 }
168
169 // comment this out to draw via bitmaps (the default)
170 err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue,
171 reinterpret_cast<void*>(model));
172 if (err) {
173 gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err);
174 }
175 return err;
176}
177
178NPError NPP_Destroy(NPP instance, NPSavedData** save)
179{
180 PluginObject *obj = (PluginObject*) instance->pdata;
181 delete obj->anim;
182 gSoundI.deleteTrack(obj->track);
183
184 return NPERR_NO_ERROR;
185}
186
187static void timer_oneshot(NPP instance, uint32 timerID) {
188 gLogI.log(instance, kDebug_ANPLogType, "-------- oneshot timer\n");
189}
190
191static int gTimerRepeatCount;
192static void timer_repeat(NPP instance, uint32 timerID) {
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400193
Grace Klobafbe47c02009-05-14 17:31:45 -0700194 gLogI.log(instance, kDebug_ANPLogType, "-------- repeat timer %d\n",
195 gTimerRepeatCount);
196 if (--gTimerRepeatCount == 0) {
197 browser->unscheduletimer(instance, timerID);
198 }
199}
200
201static void timer_neverfires(NPP instance, uint32 timerID) {
202 gLogI.log(instance, kError_ANPLogType, "-------- timer_neverfires!!!\n");
203}
204
205#define TIMER_INTERVAL 50
206
207static void timer_latency(NPP instance, uint32 timerID) {
208 PluginObject *obj = (PluginObject*) instance->pdata;
209
210 obj->mTimerCount += 1;
211
212 uint32_t now = getMSecs();
213 uint32_t interval = now - obj->mPrevTime;
214
215 uint32_t dur = now - obj->mStartTime;
216 uint32_t expectedDur = obj->mTimerCount * TIMER_INTERVAL;
217 int32_t drift = dur - expectedDur;
218 int32_t aveDrift = drift / obj->mTimerCount;
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400219
Grace Klobafbe47c02009-05-14 17:31:45 -0700220 obj->mPrevTime = now;
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400221
Grace Klobafbe47c02009-05-14 17:31:45 -0700222 gLogI.log(instance, kDebug_ANPLogType,
223 "-------- latency test: [%3d] interval %d expected %d, total %d expected %d, drift %d ave %d\n",
224 obj->mTimerCount, interval, TIMER_INTERVAL, dur, expectedDur,
225 drift, aveDrift);
226}
227
228NPError NPP_SetWindow(NPP instance, NPWindow* window)
229{
230 PluginObject *obj = (PluginObject*) instance->pdata;
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400231
Grace Klobafbe47c02009-05-14 17:31:45 -0700232 // Do nothing if browser didn't support NPN_CreateObject which would have created the PluginObject.
233 if (obj != NULL) {
234 obj->window = window;
235 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400236
Grace Klobafbe47c02009-05-14 17:31:45 -0700237 static bool gTestTimers;
238 if (!gTestTimers) {
239 gTestTimers = true;
240 // test for bogus timerID
241 browser->unscheduletimer(instance, 999999);
242 // test oneshot
243 browser->scheduletimer(instance, 100, false, timer_oneshot);
244 // test repeat
245 gTimerRepeatCount = 10;
246 browser->scheduletimer(instance, 50, true, timer_repeat);
247 // test unschedule immediately
248 uint32 id = browser->scheduletimer(instance, 100, false, timer_neverfires);
249 browser->unscheduletimer(instance, id);
250 // test double unschedlue (should be no-op)
251 browser->unscheduletimer(instance, id);
252 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400253
Grace Klobafbe47c02009-05-14 17:31:45 -0700254 if (obj->mTestTimers) {
255 browser->scheduletimer(instance, TIMER_INTERVAL, true, timer_latency);
256 obj->mStartTime = obj->mPrevTime = getMSecs();
257 obj->mTestTimers = false;
258 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400259
Mike Reed224adad2009-06-10 10:24:01 -0400260 if (true) {
261 static const struct {
262 ANPBitmapFormat fFormat;
263 const char* fName;
264 } gRecs[] = {
265 { kUnknown_ANPBitmapFormat, "unknown" },
266 { kRGBA_8888_ANPBitmapFormat, "8888" },
267 { kRGB_565_ANPBitmapFormat, "565" },
268 };
269
270 ANPPixelPacking packing;
271 for (size_t i = 0; i < ARRAY_COUNT(gRecs); i++) {
272 if (gBitmapI.getPixelPacking(gRecs[i].fFormat, &packing)) {
273 gLogI.log(instance, kDebug_ANPLogType,
274 "pixel format [%d] %s has packing ARGB [%d %d] [%d %d] [%d %d] [%d %d]\n",
275 gRecs[i].fFormat, gRecs[i].fName,
276 packing.AShift, packing.ABits,
277 packing.RShift, packing.RBits,
278 packing.GShift, packing.GBits,
279 packing.BShift, packing.BBits);
280 } else {
281 gLogI.log(instance, kDebug_ANPLogType,
282 "pixel format [%d] %s has no packing\n",
283 gRecs[i].fFormat, gRecs[i].fName);
284 }
285 }
286 }
287
Grace Klobafbe47c02009-05-14 17:31:45 -0700288 browser->invalidaterect(instance, NULL);
289
290 return NPERR_NO_ERROR;
291}
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400292
Grace Klobafbe47c02009-05-14 17:31:45 -0700293
294NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
295{
296 *stype = NP_ASFILEONLY;
297 return NPERR_NO_ERROR;
298}
299
300NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
301{
302 return NPERR_NO_ERROR;
303}
304
305int32 NPP_WriteReady(NPP instance, NPStream* stream)
306{
307 return 0;
308}
309
310int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
311{
312 return 0;
313}
314
315void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
316{
317}
318
319void NPP_Print(NPP instance, NPPrint* platformPrint)
320{
321
322}
323
324struct SoundPlay {
325 NPP instance;
326 ANPAudioTrack* track;
327 FILE* file;
328};
329
330static void audioCallback(ANPAudioEvent evt, void* user, ANPAudioBuffer* buffer) {
331 switch (evt) {
332 case kMoreData_ANPAudioEvent: {
333 SoundPlay* play = reinterpret_cast<SoundPlay*>(user);
334 size_t amount = fread(buffer->bufferData, 1, buffer->size, play->file);
335 buffer->size = amount;
336 if (amount == 0) {
337 gSoundI.stop(play->track);
338 fclose(play->file);
339 play->file = NULL;
340 // need to notify our main thread to delete the track now
341 }
342 break;
343 }
344 default:
345 break;
346 }
347}
348
349static ANPAudioTrack* createTrack(NPP instance, const char path[]) {
350 FILE* f = fopen(path, "r");
351 gLogI.log(instance, kWarning_ANPLogType, "--- path %s FILE %p", path, f);
352 if (NULL == f) {
353 return NULL;
354 }
355 SoundPlay* play = new SoundPlay;
356 play->file = f;
357 play->track = gSoundI.newTrack(44100, kPCM16Bit_ANPSampleFormat, 2, audioCallback, play);
358 if (NULL == play->track) {
359 fclose(f);
360 delete play;
361 return NULL;
362 }
363 return play->track;
364}
365
366int16 NPP_HandleEvent(NPP instance, void* event)
367{
368 PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata);
369 const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event);
370
371 switch (evt->eventType) {
372 case kDraw_ANPEventType:
Derek Sollenberger02162c12009-06-09 11:08:59 -0400373 switch (evt->data.draw.model) {
Grace Klobafbe47c02009-05-14 17:31:45 -0700374 case kBitmap_ANPDrawingModel:
Derek Sollenberger02162c12009-06-09 11:08:59 -0400375 drawPlugin(instance, evt->data.draw.data.bitmap,
376 evt->data.draw.clip);
Grace Klobafbe47c02009-05-14 17:31:45 -0700377 return 1;
378 default:
379 break; // unknown drawing model
380 }
381
382 case kKey_ANPEventType:
383 gLogI.log(instance, kDebug_ANPLogType, "---- %p Key action=%d"
384 " code=%d vcode=%d unichar=%d repeat=%d mods=%x", instance,
385 evt->data.key.action,
386 evt->data.key.nativeCode,
387 evt->data.key.virtualCode,
388 evt->data.key.unichar,
389 evt->data.key.repeatCount,
390 evt->data.key.modifiers);
391 if (evt->data.key.action == kDown_ANPKeyAction) {
392 obj->mUnichar = evt->data.key.unichar;
393 browser->invalidaterect(instance, NULL);
394 }
395 return 1;
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400396
397 case kLifecycle_ANPEventType:
398 gLogI.log(instance, kDebug_ANPLogType, "---- %p Lifecycle action=%d",
399 instance, evt->data.lifecycle.action);
Mike Reed1e7c3312009-05-26 16:37:45 -0400400 break;
Grace Klobafbe47c02009-05-14 17:31:45 -0700401
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400402 case kTouch_ANPEventType:
Grace Klobafbe47c02009-05-14 17:31:45 -0700403 gLogI.log(instance, kDebug_ANPLogType, "---- %p Touch action=%d [%d %d]",
404 instance, evt->data.touch.action, evt->data.touch.x,
405 evt->data.touch.y);
406 if (kUp_ANPTouchAction == evt->data.touch.action) {
407 if (NULL == obj->track) {
408 obj->track = createTrack(instance, "/sdcard/sample.snd");
409 }
410 if (obj->track) {
411 gLogI.log(instance, kDebug_ANPLogType, "track %p %d",
412 obj->track, gSoundI.isStopped(obj->track));
413 if (gSoundI.isStopped(obj->track)) {
414 gSoundI.start(obj->track);
415 } else {
416 gSoundI.pause(obj->track);
417 }
418 }
419 }
420 return 1;
421
422 default:
423 break;
424 }
425 return 0; // unknown or unhandled event
426}
427
428void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
429{
430
431}
432
433EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) {
434
435 if (variable == NPPVpluginNameString) {
436 const char **str = (const char **)value;
437 *str = "Test Plugin";
438 return NPERR_NO_ERROR;
439 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400440
Grace Klobafbe47c02009-05-14 17:31:45 -0700441 if (variable == NPPVpluginDescriptionString) {
442 const char **str = (const char **)value;
443 *str = "Description of Test Plugin";
444 return NPERR_NO_ERROR;
445 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400446
Grace Klobafbe47c02009-05-14 17:31:45 -0700447 return NPERR_GENERIC_ERROR;
448}
449
450NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
451{
452 if (variable == NPPVpluginScriptableNPObject) {
453 void **v = (void **)value;
454 PluginObject *obj = (PluginObject*) instance->pdata;
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400455
Grace Klobafbe47c02009-05-14 17:31:45 -0700456 if (obj)
457 browser->retainobject((NPObject*)obj);
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400458
Grace Klobafbe47c02009-05-14 17:31:45 -0700459 *v = obj;
460 return NPERR_NO_ERROR;
461 }
Derek Sollenberger9119e7d2009-06-08 10:53:09 -0400462
Grace Klobafbe47c02009-05-14 17:31:45 -0700463 return NPERR_GENERIC_ERROR;
464}
465
466NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
467{
468 return NPERR_GENERIC_ERROR;
469}
470