4936efd16134a3e2b71f887ec3283a61b2946889
[WebKit.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         }
102
103         browser->getvalue(instance, NPNVprivateModeBool, (void *)&obj->cachedPrivateBrowsingMode);
104
105         obj->pluginTest = PluginTest::create(instance, testIdentifier);
106
107         return obj->pluginTest->NPP_New(mimetype, mode, argc, argn, argv, savedData);
108     }
109
110     return NPERR_NO_ERROR;
111 }
112
113 static NPError
114 webkit_test_plugin_destroy_instance(NPP instance, NPSavedData** save)
115 {
116     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
117     if (obj) {
118         if (obj->onDestroy) {
119             executeScript(obj, obj->onDestroy);
120             free(obj->onDestroy);
121         }
122
123         if (obj->onStreamLoad)
124             free(obj->onStreamLoad);
125
126         if (obj->onStreamDestroy)
127             free(obj->onStreamDestroy);
128
129         if (obj->onURLNotify)
130             free(obj->onURLNotify);
131
132         if (obj->logDestroy)
133             pluginLog(instance, "NPP_Destroy");
134
135         if (obj->onSetWindow)
136             free(obj->onSetWindow);
137
138         obj->pluginTest->NPP_Destroy(save);
139
140         browser->releaseobject(&obj->header);
141     }
142
143     return NPERR_NO_ERROR;
144 }
145
146 static NPError
147 webkit_test_plugin_set_window(NPP instance, NPWindow *window)
148 {
149     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
150
151     if (obj) {
152         obj->lastWindow = *window;
153
154         if (obj->logSetWindow) {
155             pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
156             obj->logSetWindow = false;
157         }
158         if (obj->onSetWindow)
159             executeScript(obj, obj->onSetWindow);
160
161         if (obj->testWindowOpen) {
162             testWindowOpen(instance);
163             obj->testWindowOpen = FALSE;
164         }
165
166     }
167
168     return obj->pluginTest->NPP_SetWindow(instance, window);
169 }
170
171 static void executeScript(const PluginObject* obj, const char* script)
172 {
173     NPObject *windowScriptObject;
174     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
175
176     NPString npScript;
177     npScript.UTF8Characters = script;
178     npScript.UTF8Length = strlen(script);
179
180     NPVariant browserResult;
181     browser->evaluate(obj->npp, windowScriptObject, &npScript, &browserResult);
182     browser->releasevariantvalue(&browserResult);
183 }
184
185 static NPError
186 webkit_test_plugin_new_stream(NPP instance,
187                               NPMIMEType /*type*/,
188                               NPStream *stream,
189                               NPBool /*seekable*/,
190                               uint16_t* stype)
191 {
192     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
193     obj->stream = stream;
194     *stype = NP_NORMAL;
195
196     if (obj->returnErrorFromNewStream)
197         return NPERR_GENERIC_ERROR;
198
199     if (browser->version >= NPVERS_HAS_RESPONSE_HEADERS)
200         notifyStream(obj, stream->url, stream->headers);
201
202     if (obj->onStreamLoad)
203         executeScript(obj, obj->onStreamLoad);
204
205     return NPERR_NO_ERROR;
206 }
207
208 static NPError
209 webkit_test_plugin_destroy_stream(NPP instance, NPStream* stream, NPError reason)
210 {
211     PluginObject* obj = (PluginObject*)instance->pdata;
212
213     if (obj->onStreamDestroy) {
214         NPObject* windowObject = 0;
215         NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
216         
217         if (error == NPERR_NO_ERROR) {
218             NPVariant onStreamDestroyVariant;
219             if (browser->getproperty(instance, windowObject, browser->getstringidentifier(obj->onStreamDestroy), &onStreamDestroyVariant)) {
220                 if (NPVARIANT_IS_OBJECT(onStreamDestroyVariant)) {
221                     NPObject* onStreamDestroyFunction = NPVARIANT_TO_OBJECT(onStreamDestroyVariant);
222
223                     NPVariant reasonVariant;
224                     INT32_TO_NPVARIANT(reason, reasonVariant);
225
226                     NPVariant result;
227                     browser->invokeDefault(instance, onStreamDestroyFunction, &reasonVariant, 1, &result);
228                     browser->releasevariantvalue(&result);
229                 }
230                 browser->releasevariantvalue(&onStreamDestroyVariant);
231             }
232             browser->releaseobject(windowObject);
233         }
234     }
235
236     return obj->pluginTest->NPP_DestroyStream(stream, reason);
237 }
238
239 static void
240 webkit_test_plugin_stream_as_file(NPP /*instance*/, NPStream* /*stream*/, const char* /*fname*/)
241 {
242 }
243
244 static int32_t
245 webkit_test_plugin_write_ready(NPP /*instance*/, NPStream* /*stream*/)
246 {
247     return 4096;
248 }
249
250 static int32_t
251 webkit_test_plugin_write(NPP instance,
252                          NPStream* /*stream*/,
253                          int32_t /*offset*/,
254                          int32_t len,
255                          void* /*buffer*/)
256 {
257     PluginObject* obj = (PluginObject*)instance->pdata;
258
259     if (obj->returnNegativeOneFromWrite)
260         return -1;
261
262     return len;
263 }
264
265 static void
266 webkit_test_plugin_print(NPP /*instance*/, NPPrint* /*platformPrint*/)
267 {
268 }
269
270 static char keyEventToChar(XKeyEvent* event)
271 {
272     char c = ' ';
273     XLookupString(event, &c, sizeof(c), 0, 0);
274     return c;
275 }
276
277 static int16_t
278 webkit_test_plugin_handle_event(NPP instance, void* event)
279 {
280     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
281     if (!obj->eventLogging)
282         return 0;
283
284     XEvent* evt = static_cast<XEvent*>(event);
285
286     switch (evt->type) {
287         case ButtonRelease:
288             pluginLog(instance, "mouseUp at (%d, %d)", evt->xbutton.x, evt->xbutton.y);
289             break;
290         case ButtonPress:
291             pluginLog(instance, "mouseDown at (%d, %d)", evt->xbutton.x, evt->xbutton.y);
292             break;
293         case KeyRelease:
294             pluginLog(instance, "keyUp '%c'", keyEventToChar(&evt->xkey));
295             break;
296         case KeyPress:
297             pluginLog(instance, "keyDown '%c'", keyEventToChar(&evt->xkey));
298             break;
299         case MotionNotify:
300         case EnterNotify:
301         case LeaveNotify:
302             break;
303         case FocusIn:
304             pluginLog(instance, "getFocusEvent");
305             break;
306         case FocusOut:
307             pluginLog(instance, "loseFocusEvent");
308             break;
309         default:
310             pluginLog(instance, "event %d", evt->type);
311     }
312
313     return 0;
314 }
315
316 static void
317 webkit_test_plugin_url_notify(NPP instance, const char* url, NPReason reason, void* notifyData)
318 {
319     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
320
321     if (obj->onURLNotify)
322         executeScript(obj, obj->onURLNotify);
323
324     handleCallback(obj, url, reason, notifyData);
325 }
326
327 static NPError
328 webkit_test_plugin_get_value(NPP instance, NPPVariable variable, void *value)
329 {
330     PluginObject* obj = 0;
331     if (instance)
332         obj = static_cast<PluginObject*>(instance->pdata);
333
334     // First, check if the PluginTest object supports getting this value.
335     if (obj && obj->pluginTest->NPP_GetValue(variable, value) == NPERR_NO_ERROR)
336         return NPERR_NO_ERROR;
337     
338     NPError err = NPERR_NO_ERROR;
339
340     switch (variable) {
341         case NPPVpluginNameString:
342             *((char **)value) = const_cast<char*>("WebKit Test PlugIn");
343             break;
344         case NPPVpluginDescriptionString:
345             *((char **)value) = const_cast<char*>("Simple Netscape plug-in that handles test content for WebKit");
346             break;
347         case NPPVpluginNeedsXEmbed:
348             *((NPBool *)value) = TRUE;
349             break;
350         case NPPVpluginScriptableIID:
351         case NPPVpluginScriptableInstance:
352         case NPPVpluginScriptableNPObject:
353             err = NPERR_GENERIC_ERROR;
354             break;
355         default:
356             err = NPERR_GENERIC_ERROR;
357             break;
358     }
359
360     if (variable == NPPVpluginScriptableNPObject) {
361         void **v = (void **)value;
362         browser->retainobject((NPObject *)obj);
363         *v = obj;
364         err = NPERR_NO_ERROR;
365     }
366
367     return err;
368 }
369
370 static NPError
371 webkit_test_plugin_set_value(NPP instance, NPNVariable variable, void* value)
372 {
373     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
374
375     switch (variable) {
376         case NPNVprivateModeBool:
377             obj->cachedPrivateBrowsingMode = *(NPBool*)value;
378             return NPERR_NO_ERROR;
379         default:
380             return NPERR_GENERIC_ERROR;
381     }
382 }
383
384 char *
385 NP_GetMIMEDescription(void)
386 {
387     // We sentence-case the mime-type here to ensure that ports are not
388     // case-sensitive when loading plugins. See https://webkit.org/b/36815
389     return const_cast<char*>("application/x-Webkit-Test-Netscape:testnetscape:test netscape content");
390 }
391
392 NPError
393 NP_Initialize (NPNetscapeFuncs *aMozillaVTable, NPPluginFuncs *aPluginVTable)
394 {
395     if (aMozillaVTable == NULL || aPluginVTable == NULL)
396         return NPERR_INVALID_FUNCTABLE_ERROR;
397
398     if ((aMozillaVTable->version >> 8) > NP_VERSION_MAJOR)
399         return NPERR_INCOMPATIBLE_VERSION_ERROR;
400
401     if (aPluginVTable->size < sizeof (NPPluginFuncs))
402         return NPERR_INVALID_FUNCTABLE_ERROR;
403
404     browser = aMozillaVTable;
405     pluginFunctions = aPluginVTable;
406
407         aPluginVTable->size           = sizeof (NPPluginFuncs);
408         aPluginVTable->version        = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
409         aPluginVTable->newp           = webkit_test_plugin_new_instance;
410         aPluginVTable->destroy        = webkit_test_plugin_destroy_instance;
411         aPluginVTable->setwindow      = webkit_test_plugin_set_window;
412         aPluginVTable->newstream      = webkit_test_plugin_new_stream;
413         aPluginVTable->destroystream  = webkit_test_plugin_destroy_stream;
414         aPluginVTable->asfile         = webkit_test_plugin_stream_as_file;
415         aPluginVTable->writeready     = webkit_test_plugin_write_ready;
416         aPluginVTable->write          = webkit_test_plugin_write;
417         aPluginVTable->print          = webkit_test_plugin_print;
418         aPluginVTable->event          = webkit_test_plugin_handle_event;
419         aPluginVTable->urlnotify      = webkit_test_plugin_url_notify;
420         aPluginVTable->javaClass      = NULL;
421         aPluginVTable->getvalue       = webkit_test_plugin_get_value;
422         aPluginVTable->setvalue       = webkit_test_plugin_set_value;
423
424     return NPERR_NO_ERROR;
425 }
426
427 NPError
428 NP_Shutdown(void)
429 {
430     return NPERR_NO_ERROR;
431 }
432
433 NPError
434 NP_GetValue(void* /*future*/, NPPVariable variable, void *value)
435 {
436     return webkit_test_plugin_get_value(NULL, variable, value);
437 }