e75ca63c151d48afa714d7ebbffb43d2c6f39bd2
[WebKit-https.git] / Tools / DumpRenderTree / unix / TestNetscapePlugin / TestNetscapePlugin.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Zan Dobersek <zandobersek@gmail.com>
4  * Copyright (C) 2009 Holger Hans Peter Freyther
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "PluginObject.h"
30 #include "PluginTest.h"
31
32 #include "npapi.h"
33 #include "npruntime.h"
34 #include "npfunctions.h"
35
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <X11/Xlib.h>
41 #include <X11/Xutil.h>
42 #include <string>
43
44 using namespace std;
45  
46 extern "C" {
47     NPError NP_Initialize (NPNetscapeFuncs *aMozillaVTable, NPPluginFuncs *aPluginVTable);
48     NPError NP_Shutdown(void);
49     NPError NP_GetValue(void *future, NPPVariable variable, void *value);
50     char* NP_GetMIMEDescription(void);
51 }
52
53 static void executeScript(const PluginObject* obj, const char* script);
54
55 static NPError
56 webkit_test_plugin_new_instance(NPMIMEType mimetype,
57                                 NPP instance,
58                                 uint16_t mode,
59                                 int16_t argc,
60                                 char *argn[],
61                                 char *argv[],
62                                 NPSavedData* savedData)
63 {
64     if (browser->version >= 14) {
65         PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass());
66         instance->pdata = obj;
67
68         string testIdentifier;
69
70         for (int i = 0; i < argc; i++) {
71             if (strcasecmp(argn[i], "test") == 0)
72                 testIdentifier = argv[i];
73             else if (strcasecmp(argn[i], "onstreamload") == 0 && !obj->onStreamLoad)
74                 obj->onStreamLoad = strdup(argv[i]);
75             else if (strcasecmp(argn[i], "onStreamDestroy") == 0 && !obj->onStreamDestroy)
76                 obj->onStreamDestroy = strdup(argv[i]);
77             else if (strcasecmp(argn[i], "onURLNotify") == 0 && !obj->onURLNotify)
78                 obj->onURLNotify = strdup(argv[i]);
79             else if (strcasecmp(argn[i], "src") == 0 &&
80                      strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0)
81                 obj->returnErrorFromNewStream = TRUE;
82             else if (!strcasecmp(argn[i], "src")
83                      && !strcasecmp(argv[i], "data:application/x-webkit-test-netscape,alertwhenloaded"))
84                 executeScript(obj, "alert('Plugin Loaded!')");
85             else if (strcasecmp(argn[i], "logfirstsetwindow") == 0)
86                 obj->logSetWindow = TRUE;
87             else if (strcasecmp(argn[i], "testnpruntime") == 0)
88                 testNPRuntime(instance);
89             else if (strcasecmp(argn[i], "logSrc") == 0) {
90                 for (int i = 0; i < argc; i++)
91                     if (strcasecmp(argn[i], "src") == 0)
92                         pluginLog(instance, "src: %s", argv[i]);
93             } else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0)
94                 executeScript(obj, "document.body.innerHTML = ''");
95             else if (!strcasecmp(argn[i], "ondestroy"))
96                 obj->onDestroy = strdup(argv[i]);
97             else if (strcasecmp(argn[i], "testwindowopen") == 0)
98                 obj->testWindowOpen = TRUE;
99             else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow)
100                 obj->onSetWindow = strdup(argv[i]);
101             else if (!strcasecmp(argn[i], "windowedPlugin")) {
102                 void* windowed = 0;
103                 if (!strcasecmp(argv[i], "false") || !strcasecmp(argv[i], "0"))
104                     windowed = 0;
105                 else if (!strcasecmp(argv[i], "true") || !strcasecmp(argv[i], "1"))
106                     windowed = reinterpret_cast<void*>(1);
107                 else
108                     assert(false);
109                 browser->setvalue(instance, NPPVpluginWindowBool, windowed);
110             } else if (!strcasecmp(argn[i], "onPaintEvent") && !obj->onPaintEvent)
111                 obj->onPaintEvent = strdup(argv[i]);
112         }
113
114         browser->getvalue(instance, NPNVprivateModeBool, (void *)&obj->cachedPrivateBrowsingMode);
115
116         obj->pluginTest = PluginTest::create(instance, testIdentifier);
117
118         return obj->pluginTest->NPP_New(mimetype, mode, argc, argn, argv, savedData);
119     }
120
121     return NPERR_NO_ERROR;
122 }
123
124 static NPError
125 webkit_test_plugin_destroy_instance(NPP instance, NPSavedData** save)
126 {
127     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
128     if (obj) {
129         if (obj->onDestroy) {
130             executeScript(obj, obj->onDestroy);
131             free(obj->onDestroy);
132         }
133
134         if (obj->onStreamLoad)
135             free(obj->onStreamLoad);
136
137         if (obj->onStreamDestroy)
138             free(obj->onStreamDestroy);
139
140         if (obj->onURLNotify)
141             free(obj->onURLNotify);
142
143         if (obj->logDestroy)
144             pluginLog(instance, "NPP_Destroy");
145
146         if (obj->onSetWindow)
147             free(obj->onSetWindow);
148
149         obj->pluginTest->NPP_Destroy(save);
150
151         browser->releaseobject(&obj->header);
152     }
153
154     return NPERR_NO_ERROR;
155 }
156
157 static NPError
158 webkit_test_plugin_set_window(NPP instance, NPWindow *window)
159 {
160     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
161
162     if (obj) {
163         obj->lastWindow = *window;
164
165         if (obj->logSetWindow) {
166             pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
167             obj->logSetWindow = false;
168         }
169         if (obj->onSetWindow)
170             executeScript(obj, obj->onSetWindow);
171
172         if (obj->testWindowOpen) {
173             testWindowOpen(instance);
174             obj->testWindowOpen = FALSE;
175         }
176
177     }
178
179     return obj->pluginTest->NPP_SetWindow(instance, window);
180 }
181
182 static void executeScript(const PluginObject* obj, const char* script)
183 {
184     NPObject *windowScriptObject;
185     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
186
187     NPString npScript;
188     npScript.UTF8Characters = script;
189     npScript.UTF8Length = strlen(script);
190
191     NPVariant browserResult;
192     browser->evaluate(obj->npp, windowScriptObject, &npScript, &browserResult);
193     browser->releasevariantvalue(&browserResult);
194 }
195
196 static NPError
197 webkit_test_plugin_new_stream(NPP instance,
198                               NPMIMEType type,
199                               NPStream *stream,
200                               NPBool seekable,
201                               uint16_t* stype)
202 {
203     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
204     obj->stream = stream;
205     *stype = NP_NORMAL;
206
207     if (obj->returnErrorFromNewStream)
208         return NPERR_GENERIC_ERROR;
209
210     if (browser->version >= NPVERS_HAS_RESPONSE_HEADERS)
211         notifyStream(obj, stream->url, stream->headers);
212
213     if (obj->onStreamLoad)
214         executeScript(obj, obj->onStreamLoad);
215
216     return obj->pluginTest->NPP_NewStream(type, stream, seekable, stype);
217 }
218
219 static NPError
220 webkit_test_plugin_destroy_stream(NPP instance, NPStream* stream, NPError reason)
221 {
222     PluginObject* obj = (PluginObject*)instance->pdata;
223
224     if (obj->onStreamDestroy) {
225         NPObject* windowObject = 0;
226         NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
227         
228         if (error == NPERR_NO_ERROR) {
229             NPVariant onStreamDestroyVariant;
230             if (browser->getproperty(instance, windowObject, browser->getstringidentifier(obj->onStreamDestroy), &onStreamDestroyVariant)) {
231                 if (NPVARIANT_IS_OBJECT(onStreamDestroyVariant)) {
232                     NPObject* onStreamDestroyFunction = NPVARIANT_TO_OBJECT(onStreamDestroyVariant);
233
234                     NPVariant reasonVariant;
235                     INT32_TO_NPVARIANT(reason, reasonVariant);
236
237                     NPVariant result;
238                     browser->invokeDefault(instance, onStreamDestroyFunction, &reasonVariant, 1, &result);
239                     browser->releasevariantvalue(&result);
240                 }
241                 browser->releasevariantvalue(&onStreamDestroyVariant);
242             }
243             browser->releaseobject(windowObject);
244         }
245     }
246
247     return obj->pluginTest->NPP_DestroyStream(stream, reason);
248 }
249
250 static void
251 webkit_test_plugin_stream_as_file(NPP /*instance*/, NPStream* /*stream*/, const char* /*fname*/)
252 {
253 }
254
255 static int32_t
256 webkit_test_plugin_write_ready(NPP instance, NPStream* stream)
257 {
258     PluginObject* obj = (PluginObject*)instance->pdata;
259     return obj->pluginTest->NPP_WriteReady(stream);
260 }
261
262 static int32_t
263 webkit_test_plugin_write(NPP instance,
264                          NPStream* stream,
265                          int32_t offset,
266                          int32_t len,
267                          void* buffer)
268 {
269     PluginObject* obj = (PluginObject*)instance->pdata;
270
271     if (obj->returnNegativeOneFromWrite)
272         return -1;
273
274     return obj->pluginTest->NPP_Write(stream, offset, len, buffer);
275 }
276
277 static void
278 webkit_test_plugin_print(NPP /*instance*/, NPPrint* /*platformPrint*/)
279 {
280 }
281
282 static char keyEventToChar(XKeyEvent* event)
283 {
284     char c = ' ';
285     XLookupString(event, &c, sizeof(c), 0, 0);
286     return c;
287 }
288
289 static int16_t
290 webkit_test_plugin_handle_event(NPP instance, void* event)
291 {
292     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
293
294     XEvent* evt = static_cast<XEvent*>(event);
295
296     switch (evt->type) {
297         case ButtonRelease:
298             if (obj->eventLogging)
299                 pluginLog(instance, "mouseUp at (%d, %d)", evt->xbutton.x, evt->xbutton.y);
300             break;
301         case ButtonPress:
302             if (obj->eventLogging)
303                 pluginLog(instance, "mouseDown at (%d, %d)", evt->xbutton.x, evt->xbutton.y);
304             break;
305         case KeyRelease:
306             if (obj->eventLogging)
307                 pluginLog(instance, "keyUp '%c'", keyEventToChar(&evt->xkey));
308             break;
309         case KeyPress:
310             if (obj->eventLogging)
311                 pluginLog(instance, "keyDown '%c'", keyEventToChar(&evt->xkey));
312             break;
313         case MotionNotify:
314         case EnterNotify:
315         case LeaveNotify:
316             break;
317         case FocusIn:
318             if (obj->eventLogging)
319                 pluginLog(instance, "getFocusEvent");
320             break;
321         case FocusOut:
322             if (obj->eventLogging)
323                 pluginLog(instance, "loseFocusEvent");
324             break;
325         case GraphicsExpose:
326             if (obj->eventLogging)
327                 pluginLog(instance, "updateEvt");
328             if (obj->onPaintEvent)
329                 executeScript(obj, obj->onPaintEvent);
330             break;
331         default:
332             pluginLog(instance, "event %d", evt->type);
333     }
334
335     return 0;
336 }
337
338 static void
339 webkit_test_plugin_url_notify(NPP instance, const char* url, NPReason reason, void* notifyData)
340 {
341     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
342     if (obj->pluginTest->NPP_URLNotify(url, reason, notifyData))
343         return;
344
345     if (obj->onURLNotify)
346         executeScript(obj, obj->onURLNotify);
347
348     handleCallback(obj, url, reason, notifyData);
349 }
350
351 static NPError
352 webkit_test_plugin_get_value(NPP instance, NPPVariable variable, void *value)
353 {
354     PluginObject* obj = 0;
355     if (instance)
356         obj = static_cast<PluginObject*>(instance->pdata);
357
358     // First, check if the PluginTest object supports getting this value.
359     if (obj && obj->pluginTest->NPP_GetValue(variable, value) == NPERR_NO_ERROR)
360         return NPERR_NO_ERROR;
361     
362     NPError err = NPERR_NO_ERROR;
363
364     switch (variable) {
365         case NPPVpluginNameString:
366             *((char **)value) = const_cast<char*>("WebKit Test PlugIn");
367             break;
368         case NPPVpluginDescriptionString:
369             *((char **)value) = const_cast<char*>("Simple Netscape plug-in that handles test content for WebKit");
370             break;
371         case NPPVpluginNeedsXEmbed:
372             *((NPBool *)value) = TRUE;
373             break;
374         case NPPVpluginScriptableIID:
375         case NPPVpluginScriptableInstance:
376         case NPPVpluginScriptableNPObject:
377             err = NPERR_GENERIC_ERROR;
378             break;
379         default:
380             err = NPERR_GENERIC_ERROR;
381             break;
382     }
383
384     if (variable == NPPVpluginScriptableNPObject) {
385         void **v = (void **)value;
386         browser->retainobject((NPObject *)obj);
387         *v = obj;
388         err = NPERR_NO_ERROR;
389     }
390
391     return err;
392 }
393
394 static NPError
395 webkit_test_plugin_set_value(NPP instance, NPNVariable variable, void* value)
396 {
397     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
398
399     switch (variable) {
400         case NPNVprivateModeBool:
401             obj->cachedPrivateBrowsingMode = *(NPBool*)value;
402             return NPERR_NO_ERROR;
403         default:
404             return NPERR_GENERIC_ERROR;
405     }
406 }
407
408 char *
409 NP_GetMIMEDescription(void)
410 {
411     // We sentence-case the mime-type here to ensure that ports are not
412     // case-sensitive when loading plugins. See https://webkit.org/b/36815
413     return const_cast<char*>("application/x-Webkit-Test-Netscape:testnetscape:test netscape content;image/png:png:PNG image");
414 }
415
416 NPError
417 NP_Initialize (NPNetscapeFuncs *aMozillaVTable, NPPluginFuncs *aPluginVTable)
418 {
419     if (aMozillaVTable == NULL || aPluginVTable == NULL)
420         return NPERR_INVALID_FUNCTABLE_ERROR;
421
422     if ((aMozillaVTable->version >> 8) > NP_VERSION_MAJOR)
423         return NPERR_INCOMPATIBLE_VERSION_ERROR;
424
425     if (aPluginVTable->size < sizeof (NPPluginFuncs))
426         return NPERR_INVALID_FUNCTABLE_ERROR;
427
428     browser = aMozillaVTable;
429     pluginFunctions = aPluginVTable;
430
431         aPluginVTable->size           = sizeof (NPPluginFuncs);
432         aPluginVTable->version        = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
433         aPluginVTable->newp           = webkit_test_plugin_new_instance;
434         aPluginVTable->destroy        = webkit_test_plugin_destroy_instance;
435         aPluginVTable->setwindow      = webkit_test_plugin_set_window;
436         aPluginVTable->newstream      = webkit_test_plugin_new_stream;
437         aPluginVTable->destroystream  = webkit_test_plugin_destroy_stream;
438         aPluginVTable->asfile         = webkit_test_plugin_stream_as_file;
439         aPluginVTable->writeready     = webkit_test_plugin_write_ready;
440         aPluginVTable->write          = webkit_test_plugin_write;
441         aPluginVTable->print          = webkit_test_plugin_print;
442         aPluginVTable->event          = webkit_test_plugin_handle_event;
443         aPluginVTable->urlnotify      = webkit_test_plugin_url_notify;
444         aPluginVTable->javaClass      = NULL;
445         aPluginVTable->getvalue       = webkit_test_plugin_get_value;
446         aPluginVTable->setvalue       = webkit_test_plugin_set_value;
447
448     return NPERR_NO_ERROR;
449 }
450
451 NPError
452 NP_Shutdown(void)
453 {
454     return NPERR_NO_ERROR;
455 }
456
457 NPError
458 NP_GetValue(void* /*future*/, NPPVariable variable, void *value)
459 {
460     return webkit_test_plugin_get_value(NULL, variable, value);
461 }