blob: 4ca79ed0ecd0ad225cb0e710a629fd2747aee92f [file] [log] [blame]
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -04001/*
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 "BackgroundPlugin.h"
27#include "android_npapi.h"
28
29#include <stdio.h>
30#include <sys/time.h>
31#include <time.h>
32#include <math.h>
33#include <string.h>
34
35extern NPNetscapeFuncs* browser;
36extern ANPBitmapInterfaceV0 gBitmapI;
37extern ANPLogInterfaceV0 gLogI;
38extern ANPCanvasInterfaceV0 gCanvasI;
39extern ANPPaintInterfaceV0 gPaintI;
40extern ANPPathInterfaceV0 gPathI;
41extern ANPTypefaceInterfaceV0 gTypefaceI;
42
43extern uint32_t getMSecs();
44
45#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
46
47//#define LOG_ERROR(inst, string, params...) gLogI.log(inst, kError_ANPLogType, (log_prefix + string), inst, params)
48
49///////////////////////////////////////////////////////////////////////////////
50
51BackgroundPlugin::BackgroundPlugin(NPP inst) : SubPlugin(inst) {
52
53 m_paint = gPaintI.newPaint();
54 gPaintI.setFlags(m_paint, gPaintI.getFlags(m_paint) | kAntiAlias_ANPPaintFlag);
55 gPaintI.setColor(m_paint, 0xFFFF0000);
56 gPaintI.setTextSize(m_paint, 16);
57
58 ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle);
59 gPaintI.setTypeface(m_paint, tf);
60 gTypefaceI.unref(tf);
61
62 //initialize variables
63 mFinishedStageOne = false;
64 mFinishedStageTwo = false;
65 mFinishedStageThree = false;
66
67 // test basic plugin functionality
68 test_logging(); // android logging
69 test_timers(); // plugin timers
70 test_bitmaps(); // android bitmaps
Derek Sollenbergerc356b9f2009-07-30 16:57:07 -040071 test_domAccess();
72 test_javascript();
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -040073}
74
75BackgroundPlugin::~BackgroundPlugin() {
76}
77
Derek Sollenberger21f39912009-07-09 09:19:39 -040078bool BackgroundPlugin::supportsDrawingModel(ANPDrawingModel model) {
79 return (model == kBitmap_ANPDrawingModel);
80}
81
Derek Sollenbergerc0f26572009-07-16 11:38:02 -040082void BackgroundPlugin::drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip) {
83 ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap);
84
85 ANPRectF clipR;
86 clipR.left = clip.left;
87 clipR.top = clip.top;
88 clipR.right = clip.right;
89 clipR.bottom = clip.bottom;
90 gCanvasI.clipRect(canvas, &clipR);
91
92 draw(canvas);
93 gCanvasI.deleteCanvas(canvas);
94}
95
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -040096void BackgroundPlugin::draw(ANPCanvas* canvas) {
97
98 gCanvasI.drawColor(canvas, 0xFFFFFFFF);
99
100 ANPFontMetrics fm;
101 gPaintI.getFontMetrics(m_paint, &fm);
102
103 gPaintI.setColor(m_paint, 0xFF0000FF);
104 const char c[] = "This is a background plugin.";
105 gCanvasI.drawText(canvas, c, sizeof(c)-1, 10, -fm.fTop, m_paint);
106}
107
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400108int16 BackgroundPlugin::handleEvent(const ANPEvent* evt) {
109 NPP instance = this->inst();
110
111 switch (evt->eventType) {
112 case kDraw_ANPEventType:
113 switch (evt->data.draw.model) {
114 case kBitmap_ANPDrawingModel:
115 test_bitmap_transparency(evt);
Derek Sollenbergerc0f26572009-07-16 11:38:02 -0400116 drawPlugin(evt->data.draw.data.bitmap, evt->data.draw.clip);
Derek Sollenbergerd7ebf272009-06-18 11:19:41 -0400117 return 1;
118 default:
119 break; // unknown drawing model
120 }
121 case kTouch_ANPEventType:
122 gLogI.log(instance, kError_ANPLogType, " ------ %p the plugin did not request touch events", instance);
123 case kKey_ANPEventType:
124 gLogI.log(instance, kError_ANPLogType, " ------ %p the plugin did not request key events", instance);
125 default:
126 break;
127 }
128 return 0; // unknown or unhandled event
129}
130
131///////////////////////////////////////////////////////////////////////////////
132// LOGGING TESTS
133///////////////////////////////////////////////////////////////////////////////
134
135
136void BackgroundPlugin::test_logging() {
137 NPP instance = this->inst();
138
139 //LOG_ERROR(instance, " ------ %p Testing Log Error", instance);
140 gLogI.log(instance, kError_ANPLogType, " ------ %p Testing Log Error", instance);
141 gLogI.log(instance, kWarning_ANPLogType, " ------ %p Testing Log Warning", instance);
142 gLogI.log(instance, kDebug_ANPLogType, " ------ %p Testing Log Debug", instance);
143}
144
145///////////////////////////////////////////////////////////////////////////////
146// TIMER TESTS
147///////////////////////////////////////////////////////////////////////////////
148
149#define TIMER_INTERVAL 50
150static void timer_oneshot(NPP instance, uint32 timerID);
151static void timer_repeat(NPP instance, uint32 timerID);
152static void timer_neverfires(NPP instance, uint32 timerID);
153static void timer_latency(NPP instance, uint32 timerID);
154
155void BackgroundPlugin::test_timers() {
156 NPP instance = this->inst();
157
158 //Setup the testing counters
159 mTimerRepeatCount = 5;
160 mTimerLatencyCount = 5;
161
162 // test for bogus timerID
163 browser->unscheduletimer(instance, 999999);
164 // test one-shot
165 browser->scheduletimer(instance, 100, false, timer_oneshot);
166 // test repeat
167 browser->scheduletimer(instance, 50, true, timer_repeat);
168 // test timer latency
169 browser->scheduletimer(instance, TIMER_INTERVAL, true, timer_latency);
170 mStartTime = mPrevTime = getMSecs();
171 // test unschedule immediately
172 uint32 id = browser->scheduletimer(instance, 100, false, timer_neverfires);
173 browser->unscheduletimer(instance, id);
174 // test double unschedule (should be no-op)
175 browser->unscheduletimer(instance, id);
176
177}
178
179static void timer_oneshot(NPP instance, uint32 timerID) {
180 gLogI.log(instance, kDebug_ANPLogType, "-------- oneshot timer\n");
181}
182
183static void timer_repeat(NPP instance, uint32 timerID) {
184 BackgroundPlugin *obj = ((BackgroundPlugin*) ((PluginObject*) instance->pdata)->activePlugin);
185
186 gLogI.log(instance, kDebug_ANPLogType, "-------- repeat timer %d\n",
187 obj->mTimerRepeatCount);
188 if (--obj->mTimerRepeatCount == 0) {
189 browser->unscheduletimer(instance, timerID);
190 }
191}
192
193static void timer_neverfires(NPP instance, uint32 timerID) {
194 gLogI.log(instance, kError_ANPLogType, "-------- timer_neverfires!!!\n");
195}
196
197static void timer_latency(NPP instance, uint32 timerID) {
198 BackgroundPlugin *obj = ((BackgroundPlugin*) ((PluginObject*) instance->pdata)->activePlugin);
199
200 obj->mTimerLatencyCurrentCount += 1;
201
202 uint32_t now = getMSecs();
203 uint32_t interval = now - obj->mPrevTime;
204 uint32_t dur = now - obj->mStartTime;
205 uint32_t expectedDur = obj->mTimerLatencyCurrentCount * TIMER_INTERVAL;
206 int32_t drift = dur - expectedDur;
207 int32_t avgDrift = drift / obj->mTimerLatencyCurrentCount;
208
209 obj->mPrevTime = now;
210
211 gLogI.log(instance, kDebug_ANPLogType,
212 "-------- latency test: [%3d] interval %d expected %d, total %d expected %d, drift %d avg %d\n",
213 obj->mTimerLatencyCurrentCount, interval, TIMER_INTERVAL, dur,
214 expectedDur, drift, avgDrift);
215
216 if (--obj->mTimerLatencyCount == 0) {
217 browser->unscheduletimer(instance, timerID);
218 }
219}
220
221///////////////////////////////////////////////////////////////////////////////
222// BITMAP TESTS
223///////////////////////////////////////////////////////////////////////////////
224
225static void test_formats(NPP instance);
226
227void BackgroundPlugin::test_bitmaps() {
228 test_formats(this->inst());
229}
230
231static void test_formats(NPP instance) {
232
233 // TODO pull names from enum in npapi instead of hardcoding them
234 static const struct {
235 ANPBitmapFormat fFormat;
236 const char* fName;
237 } gRecs[] = {
238 { kUnknown_ANPBitmapFormat, "unknown" },
239 { kRGBA_8888_ANPBitmapFormat, "8888" },
240 { kRGB_565_ANPBitmapFormat, "565" },
241 };
242
243 ANPPixelPacking packing;
244 for (size_t i = 0; i < ARRAY_COUNT(gRecs); i++) {
245 if (gBitmapI.getPixelPacking(gRecs[i].fFormat, &packing)) {
246 gLogI.log(instance, kDebug_ANPLogType,
247 "pixel format [%d] %s has packing ARGB [%d %d] [%d %d] [%d %d] [%d %d]\n",
248 gRecs[i].fFormat, gRecs[i].fName,
249 packing.AShift, packing.ABits,
250 packing.RShift, packing.RBits,
251 packing.GShift, packing.GBits,
252 packing.BShift, packing.BBits);
253 } else {
254 gLogI.log(instance, kDebug_ANPLogType,
255 "pixel format [%d] %s has no packing\n",
256 gRecs[i].fFormat, gRecs[i].fName);
257 }
258 }
259}
260
261void BackgroundPlugin::test_bitmap_transparency(const ANPEvent* evt) {
262 NPP instance = this->inst();
263
264 // check default & set transparent
265 if (!mFinishedStageOne) {
266
267 gLogI.log(instance, kDebug_ANPLogType, "BEGIN: testing bitmap transparency");
268
269 //check to make sure it is not transparent
270 if (evt->data.draw.data.bitmap.format == kRGBA_8888_ANPBitmapFormat) {
271 gLogI.log(instance, kError_ANPLogType, "bitmap default format is transparent");
272 }
273
274 //make it transparent (any non-null value will set it to true)
275 bool value = true;
276 NPError err = browser->setvalue(instance, NPPVpluginTransparentBool, &value);
277 if (err != NPERR_NO_ERROR) {
278 gLogI.log(instance, kError_ANPLogType, "Error setting transparency.");
279 }
280
281 mFinishedStageOne = true;
282 browser->invalidaterect(instance, NULL);
283 }
284 // check transparent & set opaque
285 else if (!mFinishedStageTwo) {
286
287 //check to make sure it is transparent
288 if (evt->data.draw.data.bitmap.format != kRGBA_8888_ANPBitmapFormat) {
289 gLogI.log(instance, kError_ANPLogType, "bitmap did not change to transparent format");
290 }
291
292 //make it opaque
293 NPError err = browser->setvalue(instance, NPPVpluginTransparentBool, NULL);
294 if (err != NPERR_NO_ERROR) {
295 gLogI.log(instance, kError_ANPLogType, "Error setting transparency.");
296 }
297
298 mFinishedStageTwo = true;
299 }
300 // check opaque
301 else if (!mFinishedStageThree) {
302
303 //check to make sure it is not transparent
304 if (evt->data.draw.data.bitmap.format == kRGBA_8888_ANPBitmapFormat) {
305 gLogI.log(instance, kError_ANPLogType, "bitmap default format is transparent");
306 }
307
308 gLogI.log(instance, kDebug_ANPLogType, "END: testing bitmap transparency");
309
310 mFinishedStageThree = true;
311 }
312}
Derek Sollenbergerc356b9f2009-07-30 16:57:07 -0400313
314///////////////////////////////////////////////////////////////////////////////
315// DOM TESTS
316///////////////////////////////////////////////////////////////////////////////
317
318void BackgroundPlugin::test_domAccess() {
319 NPP instance = this->inst();
320
321 gLogI.log(instance, kDebug_ANPLogType, " ------ %p Testing DOM Access", instance);
322
323 // Get the plugin's DOM object
324 NPObject* windowObject = NULL;
325 browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
326
327 if (!windowObject)
328 gLogI.log(instance, kError_ANPLogType, " ------ %p Unable to retrieve DOM Window", instance);
329
330 // Retrieve a property from the plugin's DOM object
331 NPIdentifier topIdentifier = browser->getstringidentifier("top");
332 NPVariant topObjectVariant;
333 browser->getproperty(instance, windowObject, topIdentifier, &topObjectVariant);
334
335 if (topObjectVariant.type != NPVariantType_Object)
336 gLogI.log(instance, kError_ANPLogType, " ------ %p Invalid Variant type for DOM Property: %d,%d", instance, topObjectVariant.type, NPVariantType_Object);
337}
338
339
340///////////////////////////////////////////////////////////////////////////////
341// JAVASCRIPT TESTS
342///////////////////////////////////////////////////////////////////////////////
343
344
345void BackgroundPlugin::test_javascript() {
346 NPP instance = this->inst();
347
348 gLogI.log(instance, kDebug_ANPLogType, " ------ %p Testing JavaScript Access", instance);
349
350 // Get the plugin's DOM object
351 NPObject* windowObject = NULL;
352 browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
353
354 if (!windowObject)
355 gLogI.log(instance, kError_ANPLogType, " ------ %p Unable to retrieve DOM Window", instance);
356
357 // create a string (JS code) that is stored in memory allocated by the browser
358 const char* jsString = "1200 + 34";
359 void* stringMem = browser->memalloc(strlen(jsString));
360 memcpy(stringMem, jsString, strlen(jsString));
361
362 // execute the javascript in the plugin's DOM object
363 NPString script = { (char*)stringMem, strlen(jsString) };
364 NPVariant scriptVariant;
365 if (!browser->evaluate(instance, windowObject, &script, &scriptVariant))
366 gLogI.log(instance, kError_ANPLogType, " ------ %p Unable to eval the JS.", instance);
367
368 if (scriptVariant.type == NPVariantType_Int32) {
369 if (scriptVariant.value.intValue != 1234)
370 gLogI.log(instance, kError_ANPLogType, " ------ %p Invalid Value for JS Return: %d,1234", instance, scriptVariant.value.intValue);
371 } else {
372 gLogI.log(instance, kError_ANPLogType, " ------ %p Invalid Variant type for JS Return: %d,%d", instance, scriptVariant.type, NPVariantType_Int32);
373 }
374
375 // free the memory allocated within the browser
376 browser->memfree(stringMem);
377}