4cd1a62805538189e4353fa52d2b0b5852922118
[WebKit.git] / Tools / DumpRenderTree / TestNetscapePlugIn / main.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. 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 APPLE INC. ``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 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 "PluginObject.h"
27
28 #include "PluginTest.h"
29 #include <cstdlib>
30 #include <cstring>
31 #include <string>
32
33 #if defined(MOZ_X11)
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36 #endif
37
38 #if !defined(NP_NO_CARBON) && defined(QD_HEADERS_ARE_PRIVATE) && QD_HEADERS_ARE_PRIVATE
39 extern "C" void GlobalToLocal(Point*);
40 #endif
41
42 using namespace std;
43
44 static bool getEntryPointsWasCalled;
45 static bool initializeWasCalled;
46
47 #if defined(XP_WIN)
48 #define STDCALL __stdcall
49
50 static inline int strcasecmp(const char* s1, const char* s2)
51 {
52     return _stricmp(s1, s2);
53 }
54
55 #else
56 #define STDCALL
57 #endif
58
59 extern "C" {
60 NPError STDCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs);
61 }
62
63 // Entry points
64 extern "C"
65 NPError STDCALL NP_Initialize(NPNetscapeFuncs *browserFuncs
66 #if defined(XP_UNIX)
67                               , NPPluginFuncs *pluginFuncs
68 #endif
69                               )
70 {
71     initializeWasCalled = true;
72
73 #if defined(XP_WIN)
74     // Simulate Flash and QuickTime's behavior of crashing when NP_Initialize is called before NP_GetEntryPoints.
75     if (!getEntryPointsWasCalled)
76         CRASH();
77 #endif
78
79     browser = browserFuncs;
80
81 #if defined(XP_UNIX)
82     return NP_GetEntryPoints(pluginFuncs);
83 #else
84     return NPERR_NO_ERROR;
85 #endif
86 }
87
88 extern "C"
89 NPError STDCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs)
90 {
91     getEntryPointsWasCalled = true;
92
93 #ifdef XP_MACOSX
94     // Simulate Silverlight's behavior of crashing when NP_GetEntryPoints is called before NP_Initialize.
95     if (!initializeWasCalled)
96         CRASH();
97 #endif
98
99     pluginFunctions = pluginFuncs;
100
101     pluginFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
102     pluginFuncs->size = sizeof(pluginFuncs);
103     pluginFuncs->newp = NPP_New;
104     pluginFuncs->destroy = NPP_Destroy;
105     pluginFuncs->setwindow = NPP_SetWindow;
106     pluginFuncs->newstream = NPP_NewStream;
107     pluginFuncs->destroystream = NPP_DestroyStream;
108     pluginFuncs->asfile = NPP_StreamAsFile;
109     pluginFuncs->writeready = NPP_WriteReady;
110     pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
111     pluginFuncs->print = NPP_Print;
112     pluginFuncs->event = NPP_HandleEvent;
113     pluginFuncs->urlnotify = NPP_URLNotify;
114     pluginFuncs->urlredirectnotify = NPP_URLRedirectNotify;
115     pluginFuncs->getvalue = NPP_GetValue;
116     pluginFuncs->setvalue = NPP_SetValue;
117     
118     return NPERR_NO_ERROR;
119 }
120
121 extern "C"
122 void STDCALL NP_Shutdown(void)
123 {
124     PluginTest::NP_Shutdown();
125 }
126
127 static void executeScript(const PluginObject* obj, const char* script);
128
129 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
130 {
131 #ifdef XP_MACOSX
132     NPEventModel eventModel;
133     
134     // Always turn on the CG model
135     NPBool supportsCoreGraphics;
136     if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR)
137         supportsCoreGraphics = false;
138     
139     if (!supportsCoreGraphics)
140         return NPERR_INCOMPATIBLE_VERSION_ERROR;
141
142     NPDrawingModel drawingModelToUse = NPDrawingModelCoreGraphics;
143
144     NPBool supportsCoreAnimation;
145     if (browser->getvalue(instance, NPNVsupportsCoreAnimationBool, &supportsCoreAnimation) != NPERR_NO_ERROR)
146         supportsCoreAnimation = false;
147
148 #ifndef NP_NO_CARBON
149     NPBool supportsCarbon = false;
150 #endif
151     NPBool supportsCocoa = false;
152
153 #ifndef NP_NO_CARBON
154     // A browser that doesn't know about NPNVsupportsCarbonBool is one that only supports Carbon event model.
155     if (browser->getvalue(instance, NPNVsupportsCarbonBool, &supportsCarbon) != NPERR_NO_ERROR)
156         supportsCarbon = true;
157 #endif
158
159     if (browser->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR)
160         supportsCocoa = false;
161
162     if (supportsCocoa) {
163         eventModel = NPEventModelCocoa;
164 #ifndef NP_NO_CARBON
165     } else if (supportsCarbon) {
166         eventModel = NPEventModelCarbon;
167 #endif
168     } else {
169         return NPERR_INCOMPATIBLE_VERSION_ERROR;
170     }
171
172      browser->setvalue(instance, NPPVpluginEventModel, (void *)eventModel);
173 #endif // XP_MACOSX
174
175     PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass());
176     instance->pdata = obj;
177
178 #ifdef XP_MACOSX
179     obj->eventModel = eventModel;
180     obj->coreAnimationLayer = 0;
181 #endif // XP_MACOSX
182
183     string testIdentifier;
184     const char* onNewScript = 0;
185     
186     for (int i = 0; i < argc; i++) {
187         if (strcasecmp(argn[i], "test") == 0)
188             testIdentifier = argv[i];
189         if (strcasecmp(argn[i], "onstreamload") == 0 && !obj->onStreamLoad)
190             obj->onStreamLoad = strdup(argv[i]);
191         else if (strcasecmp(argn[i], "onStreamDestroy") == 0 && !obj->onStreamDestroy)
192             obj->onStreamDestroy = strdup(argv[i]);
193         else if (strcasecmp(argn[i], "onURLNotify") == 0 && !obj->onURLNotify)
194             obj->onURLNotify = strdup(argv[i]);
195         else if (strcasecmp(argn[i], "src") == 0 &&
196                  strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0)
197             obj->returnErrorFromNewStream = TRUE;
198         else if (strcasecmp(argn[i], "src") == 0 &&
199                  strcasecmp(argv[i], "data:application/x-webkit-test-netscape,alertwhenloaded") == 0)
200             executeScript(obj, "alert('Plugin Loaded!')");
201         else if (strcasecmp(argn[i], "src") == 0 &&
202                  strcasecmp(argv[i], "data:application/x-webkit-test-netscape,logifloaded") == 0) {
203             for (int j = 0; j < argc; j++) {
204               if (strcasecmp(argn[j], "log") == 0) {
205                 int length = 26 + strlen(argv[j]) + 1;
206                 char* buffer = (char*) malloc(length);
207                 snprintf(buffer, length, "xWebkitTestNetscapeLog('%s')", argv[j]);
208                 executeScript(obj, buffer);
209                 free(buffer);
210               }
211             }
212         } else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow)
213             obj->onSetWindow = strdup(argv[i]);
214         else if (strcasecmp(argn[i], "onNew") == 0 && !onNewScript)
215             onNewScript = argv[i];
216         else if (strcasecmp(argn[i], "onPaintEvent") == 0 && !obj->onPaintEvent)
217             obj->onPaintEvent = strdup(argv[i]);
218         else if (strcasecmp(argn[i], "logfirstsetwindow") == 0)
219             obj->logSetWindow = TRUE;
220         else if (strcasecmp(argn[i], "testnpruntime") == 0)
221             testNPRuntime(instance);
222         else if (strcasecmp(argn[i], "logSrc") == 0) {
223             for (int i = 0; i < argc; i++)
224                 if (strcasecmp(argn[i], "src") == 0)
225                     pluginLog(instance, "src: %s", argv[i]);
226         } else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0)
227             executeScript(obj, "document.body.innerHTML = ''");
228         else if (!strcasecmp(argn[i], "ondestroy"))
229             obj->onDestroy = strdup(argv[i]);
230         else if (strcasecmp(argn[i], "testwindowopen") == 0)
231             obj->testWindowOpen = TRUE;
232         else if (strcasecmp(argn[i], "drawingmodel") == 0) {
233 #ifdef XP_MACOSX
234             const char* value = argv[i];
235             if (strcasecmp(value, "coreanimation") == 0) {
236                 if (supportsCoreAnimation)
237                     drawingModelToUse = NPDrawingModelCoreAnimation;
238                 else
239                     return NPERR_INCOMPATIBLE_VERSION_ERROR;
240              } else if (strcasecmp(value, "coregraphics") == 0) {
241                 if (supportsCoreGraphics)
242                     drawingModelToUse = NPDrawingModelCoreGraphics;
243                 else
244                     return NPERR_INCOMPATIBLE_VERSION_ERROR;
245              } else
246                 return NPERR_INCOMPATIBLE_VERSION_ERROR;
247 #endif
248         } else if (strcasecmp(argn[i], "testGetURLOnDestroy") == 0) {
249 #if defined(XP_WIN)
250             // FIXME: When https://bugs.webkit.org/show_bug.cgi?id=41831 is fixed, this #ifdef can be removed.
251             obj->testGetURLOnDestroy = TRUE;
252 #endif
253         } else if (!strcasecmp(argn[i], "src") && strstr(argv[i], "plugin-document-has-focus.pl"))
254             obj->testKeyboardFocusForPlugins = TRUE;
255         else if (!strcasecmp(argn[i], "src") && strstr(argv[i], "plugin-document-alert-and-notify-done.pl"))
256             executeScript(obj, "alert('Plugin Loaded!'); testRunner.notifyDone();");
257         else if (!strcasecmp(argn[i], "evaluatescript")) {
258             char* script = argv[i];
259             if (script == strstr(script, "mouse::")) {
260                 obj->mouseDownForEvaluateScript = true;
261                 obj->evaluateScriptOnMouseDownOrKeyDown = strdup(script + sizeof("mouse::") - 1);
262             } else if (script == strstr(script, "key::")) {
263                 obj->evaluateScriptOnMouseDownOrKeyDown = strdup(script + sizeof("key::") - 1);
264             }
265             // When testing evaluate script on mouse-down or key-down, allow event logging to handle events.
266             if (obj->evaluateScriptOnMouseDownOrKeyDown)
267                 obj->eventLogging = true;
268         } else if (!strcasecmp(argn[i], "windowedPlugin")) {
269             void* windowed = 0;
270             if (!strcasecmp(argv[i], "false") || !strcasecmp(argv[i], "0"))
271                 windowed = 0;
272             else if (!strcasecmp(argv[i], "true") || !strcasecmp(argv[i], "1"))
273                 windowed = reinterpret_cast<void*>(1);
274             else
275                 assert(false);
276             browser->setvalue(instance, NPPVpluginWindowBool, windowed);
277         }
278     }
279
280 #ifdef XP_MACOSX
281     browser->setvalue(instance, NPPVpluginDrawingModel, (void *)drawingModelToUse);
282     if (drawingModelToUse == NPDrawingModelCoreAnimation)
283         obj->coreAnimationLayer = createCoreAnimationLayer();
284 #endif
285
286     obj->pluginTest = PluginTest::create(instance, testIdentifier);
287
288     if (!obj->pluginTest) {
289         pluginLog(instance, "NPP_New: Could not find a test named \"%s\", maybe its .cpp file wasn't added to the build system?", testIdentifier.c_str());
290         return NPERR_GENERIC_ERROR;
291     }
292
293     if (onNewScript)
294         executeScript(obj, onNewScript);
295
296     return obj->pluginTest->NPP_New(pluginType, mode, argc, argn, argv, saved);
297 }
298
299 NPError NPP_Destroy(NPP instance, NPSavedData **save)
300 {
301     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
302     if (obj) {
303         if (obj->testGetURLOnDestroy)
304             browser->geturlnotify(obj->npp, "about:blank", "", 0);
305
306         if (obj->onDestroy) {
307             executeScript(obj, obj->onDestroy);
308             free(obj->onDestroy);
309         }
310
311         if (obj->onStreamLoad)
312             free(obj->onStreamLoad);
313
314         if (obj->onStreamDestroy)
315             free(obj->onStreamDestroy);
316
317         if (obj->onURLNotify)
318             free(obj->onURLNotify);
319
320         if (obj->onSetWindow)
321             free(obj->onSetWindow);
322
323         if (obj->onPaintEvent)
324             free(obj->onPaintEvent);
325
326         if (obj->evaluateScriptOnMouseDownOrKeyDown)
327             free(obj->evaluateScriptOnMouseDownOrKeyDown);
328
329         if (obj->logDestroy)
330             pluginLog(instance, "NPP_Destroy");
331
332 #ifdef XP_MACOSX
333         if (obj->coreAnimationLayer)
334             CFRelease(obj->coreAnimationLayer);
335 #endif
336
337         if (obj->pluginTest)
338             obj->pluginTest->NPP_Destroy(save);
339
340         browser->releaseobject(&obj->header);
341     }
342     return NPERR_NO_ERROR;
343 }
344
345 NPError NPP_SetWindow(NPP instance, NPWindow *window)
346 {
347     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
348
349     if (!obj)
350         return NPERR_GENERIC_ERROR;
351
352     obj->lastWindow = *window;
353
354     if (obj->logSetWindow) {
355         pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
356         obj->logSetWindow = FALSE;
357         executeScript(obj, "testRunner.notifyDone();");
358     }
359
360     if (obj->onSetWindow)
361         executeScript(obj, obj->onSetWindow);
362
363     if (obj->testWindowOpen) {
364         testWindowOpen(instance);
365         obj->testWindowOpen = FALSE;
366     }
367
368     if (obj->testKeyboardFocusForPlugins) {
369         obj->eventLogging = true;
370         executeScript(obj, "eventSender.keyDown('A');");
371     }
372
373     return obj->pluginTest->NPP_SetWindow(window);
374 }
375
376 static void executeScript(const PluginObject* obj, const char* script)
377 {
378     NPObject *windowScriptObject;
379     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
380
381     NPString npScript;
382     npScript.UTF8Characters = script;
383     npScript.UTF8Length = strlen(script);
384
385     NPVariant browserResult;
386     browser->evaluate(obj->npp, windowScriptObject, &npScript, &browserResult);
387     browser->releasevariantvalue(&browserResult);
388 }
389
390 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16_t *stype)
391 {
392     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
393     obj->stream = stream;
394     *stype = NP_NORMAL;
395
396     if (obj->returnErrorFromNewStream)
397         return NPERR_GENERIC_ERROR;
398     
399     if (browser->version >= NPVERS_HAS_RESPONSE_HEADERS)
400         notifyStream(obj, stream->url, stream->headers);
401
402     if (obj->onStreamLoad)
403         executeScript(obj, obj->onStreamLoad);
404
405     return obj->pluginTest->NPP_NewStream(type, stream, seekable, stype);
406 }
407
408 NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
409 {
410     PluginObject* obj = (PluginObject*)instance->pdata;
411
412     if (obj->onStreamDestroy) {
413         NPObject* windowObject = 0;
414         NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
415         
416         if (error == NPERR_NO_ERROR) {
417             NPVariant onStreamDestroyVariant;
418             if (browser->getproperty(instance, windowObject, browser->getstringidentifier(obj->onStreamDestroy), &onStreamDestroyVariant)) {
419                 if (NPVARIANT_IS_OBJECT(onStreamDestroyVariant)) {
420                     NPObject* onStreamDestroyFunction = NPVARIANT_TO_OBJECT(onStreamDestroyVariant);
421
422                     NPVariant reasonVariant;
423                     INT32_TO_NPVARIANT(reason, reasonVariant);
424
425                     NPVariant result;
426                     browser->invokeDefault(instance, onStreamDestroyFunction, &reasonVariant, 1, &result);
427                     browser->releasevariantvalue(&result);
428                 }
429                 browser->releasevariantvalue(&onStreamDestroyVariant);
430             }
431             browser->releaseobject(windowObject);
432         }
433     }
434
435     return obj->pluginTest->NPP_DestroyStream(stream, reason);
436 }
437
438 int32_t NPP_WriteReady(NPP instance, NPStream *stream)
439 {
440     PluginObject* obj = (PluginObject*)instance->pdata;
441     return obj->pluginTest->NPP_WriteReady(stream);
442 }
443
444 int32_t NPP_Write(NPP instance, NPStream *stream, int32_t offset, int32_t len, void *buffer)
445 {
446     PluginObject* obj = (PluginObject*)instance->pdata;
447
448     if (obj->returnNegativeOneFromWrite)
449         return -1;
450
451     return obj->pluginTest->NPP_Write(stream, offset, len, buffer);
452 }
453
454 void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname)
455 {
456 }
457
458 void NPP_Print(NPP instance, NPPrint *platformPrint)
459 {
460 }
461
462 #ifdef XP_MACOSX
463 #ifndef NP_NO_CARBON
464 static int16_t handleEventCarbon(NPP instance, PluginObject* obj, EventRecord* event)
465 {
466     Point pt = { event->where.v, event->where.h };
467
468     switch (event->what) {
469         case nullEvent:
470             // these are delivered non-deterministically, don't log.
471             break;
472         case mouseDown:
473             if (obj->eventLogging) {
474 #if __clang__
475 #pragma clang diagnostic push
476 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
477 #endif
478                 GlobalToLocal(&pt);
479 #if __clang__
480 #pragma clang diagnostic pop
481 #endif
482                 pluginLog(instance, "mouseDown at (%d, %d)", pt.h, pt.v);
483             }
484             if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
485                 executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
486             break;
487         case mouseUp:
488             if (obj->eventLogging) {
489 #if __clang__
490 #pragma clang diagnostic push
491 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
492 #endif
493                 GlobalToLocal(&pt);
494 #if __clang__
495 #pragma clang diagnostic pop
496 #endif
497                 pluginLog(instance, "mouseUp at (%d, %d)", pt.h, pt.v);
498             }
499             break;
500         case keyDown:
501             if (obj->eventLogging)
502                 pluginLog(instance, "keyDown '%c'", (char)(event->message & 0xFF));
503             if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
504                 executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
505             break;
506         case keyUp:
507             if (obj->eventLogging)
508                 pluginLog(instance, "keyUp '%c'", (char)(event->message & 0xFF));
509             if (obj->testKeyboardFocusForPlugins) {
510                 obj->eventLogging = false;
511                 obj->testKeyboardFocusForPlugins = FALSE;
512                 executeScript(obj, "testRunner.notifyDone();");
513             }
514             break;
515         case autoKey:
516             if (obj->eventLogging)
517                 pluginLog(instance, "autoKey '%c'", (char)(event->message & 0xFF));
518             break;
519         case updateEvt:
520             if (obj->eventLogging)
521                 pluginLog(instance, "updateEvt");
522             break;
523         case diskEvt:
524             if (obj->eventLogging)
525                 pluginLog(instance, "diskEvt");
526             break;
527         case activateEvt:
528             if (obj->eventLogging)
529                 pluginLog(instance, "activateEvt");
530             break;
531         case osEvt:
532             if (!obj->eventLogging)
533                 break;
534             printf("PLUGIN: osEvt - ");
535             switch ((event->message & 0xFF000000) >> 24) {
536                 case suspendResumeMessage:
537                     printf("%s\n", (event->message & 0x1) ? "resume" : "suspend");
538                     break;
539                 case mouseMovedMessage:
540                     printf("mouseMoved\n");
541                     break;
542                 default:
543                     printf("%08lX\n", event->message);
544             }
545             break;
546         case kHighLevelEvent:
547             if (obj->eventLogging)
548                 pluginLog(instance, "kHighLevelEvent");
549             break;
550         // NPAPI events
551         case NPEventType_GetFocusEvent:
552             if (obj->eventLogging)
553                 pluginLog(instance, "getFocusEvent");
554             break;
555         case NPEventType_LoseFocusEvent:
556             if (obj->eventLogging)
557                 pluginLog(instance, "loseFocusEvent");
558             break;
559         case NPEventType_AdjustCursorEvent:
560             if (obj->eventLogging)
561                 pluginLog(instance, "adjustCursorEvent");
562             break;
563         default:
564             if (obj->eventLogging)
565                 pluginLog(instance, "event %d", event->what);
566     }
567     
568     return 0;
569 }
570 #endif
571
572 static int16_t handleEventCocoa(NPP instance, PluginObject* obj, NPCocoaEvent* event)
573 {
574     switch (event->type) {
575         case NPCocoaEventWindowFocusChanged:
576             
577         case NPCocoaEventFocusChanged:
578             if (obj->eventLogging) {
579                 if (event->data.focus.hasFocus)
580                     pluginLog(instance, "getFocusEvent");
581                 else
582                     pluginLog(instance, "loseFocusEvent");
583             }
584             return 1;
585
586         case NPCocoaEventDrawRect: {
587             if (obj->onPaintEvent)
588                 executeScript(obj, obj->onPaintEvent);
589             return 1;
590         }
591
592         case NPCocoaEventKeyDown:
593             if (obj->eventLogging && event->data.key.characters)
594                 pluginLog(instance, "keyDown '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0));
595             if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
596                 executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
597             return 1;
598
599         case NPCocoaEventKeyUp:
600             if (obj->eventLogging && event->data.key.characters) {
601                 pluginLog(instance, "keyUp '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0));
602                 if (obj->testKeyboardFocusForPlugins) {
603                     obj->eventLogging = false;
604                     obj->testKeyboardFocusForPlugins = FALSE;
605                     executeScript(obj, "testRunner.notifyDone();");
606                 }
607             }
608             return 1;
609
610         case NPCocoaEventFlagsChanged:
611             return 1;
612
613         case NPCocoaEventMouseDown:
614             if (obj->eventLogging) {
615                 pluginLog(instance, "mouseDown at (%d, %d)", 
616                        (int)event->data.mouse.pluginX,
617                        (int)event->data.mouse.pluginY);
618             }
619             if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
620                 executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
621             return 1;
622         case NPCocoaEventMouseUp:
623             if (obj->eventLogging) {
624                 pluginLog(instance, "mouseUp at (%d, %d)", 
625                        (int)event->data.mouse.pluginX,
626                        (int)event->data.mouse.pluginY);
627             }
628             return 1;
629             
630         case NPCocoaEventMouseMoved:
631         case NPCocoaEventMouseEntered:
632         case NPCocoaEventMouseExited:
633         case NPCocoaEventMouseDragged:
634         case NPCocoaEventScrollWheel:
635         case NPCocoaEventTextInput:
636             return 1;
637     }
638     
639     return 0;
640 }
641
642 #endif // XP_MACOSX
643
644 #if defined(MOZ_X11)
645 static char keyEventToChar(XKeyEvent* event)
646 {
647     char c = ' ';
648     XLookupString(event, &c, sizeof(c), 0, 0);
649     return c;
650 }
651
652 static int16_t handleEventX11(NPP instance, PluginObject* obj, XEvent* event)
653 {
654     switch (event->type) {
655     case ButtonPress:
656         if (obj->eventLogging)
657             pluginLog(instance, "mouseDown at (%d, %d)", event->xbutton.x, event->xbutton.y);
658         if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
659             executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
660         break;
661     case ButtonRelease:
662         if (obj->eventLogging)
663             pluginLog(instance, "mouseUp at (%d, %d)", event->xbutton.x, event->xbutton.y);
664         break;
665     case KeyPress:
666         // FIXME: extract key code
667         if (obj->eventLogging)
668             pluginLog(instance, "keyDown '%c'", keyEventToChar(&event->xkey));
669         if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
670             executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
671         break;
672     case KeyRelease:
673         // FIXME: extract key code
674         if (obj->eventLogging)
675             pluginLog(instance, "keyUp '%c'", keyEventToChar(&event->xkey));
676         if (obj->testKeyboardFocusForPlugins) {
677             obj->eventLogging = false;
678             obj->testKeyboardFocusForPlugins = FALSE;
679             executeScript(obj, "testRunner.notifyDone();");
680         }
681         break;
682     case GraphicsExpose:
683         if (obj->eventLogging)
684             pluginLog(instance, "updateEvt");
685         if (obj->onPaintEvent)
686             executeScript(obj, obj->onPaintEvent);
687         break;
688     // NPAPI events
689     case FocusIn:
690         if (obj->eventLogging)
691             pluginLog(instance, "getFocusEvent");
692         break;
693     case FocusOut:
694         if (obj->eventLogging)
695             pluginLog(instance, "loseFocusEvent");
696         break;
697     case EnterNotify:
698     case LeaveNotify:
699     case MotionNotify:
700         break;
701     default:
702         if (obj->eventLogging)
703             pluginLog(instance, "event %d", event->type);
704     }
705
706     fflush(stdout);
707     return 0;
708 }
709 #endif // MOZ_X11
710
711 #ifdef XP_WIN
712 static int16_t handleEventWin(NPP instance, PluginObject* obj, NPEvent* event)
713 {
714     switch (event->event) {
715     case WM_PAINT:
716         if (obj->onPaintEvent)
717             executeScript(obj, obj->onPaintEvent);
718         break;
719     case WM_KEYDOWN:
720         if (obj->eventLogging)
721             pluginLog(instance, "keyDown '%c'", event->wParam);
722         if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
723             executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
724         break;
725     case WM_CHAR:
726         break;
727     case WM_KEYUP:
728         if (obj->eventLogging)
729             pluginLog(instance, "keyUp '%c'", event->wParam);
730         if (obj->testKeyboardFocusForPlugins) {
731             obj->eventLogging = false;
732             obj->testKeyboardFocusForPlugins = FALSE;
733             executeScript(obj, "testRunner.notifyDone();");
734         }
735         break;
736     case WM_LBUTTONDOWN:
737     case WM_MBUTTONDOWN:
738     case WM_RBUTTONDOWN:
739         if (obj->eventLogging)
740             pluginLog(instance, "mouseDown at (%d, %d)", LOWORD(event->lParam), HIWORD(event->lParam));
741         if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
742             executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
743         break;
744     case WM_LBUTTONUP:
745     case WM_MBUTTONUP:
746     case WM_RBUTTONUP:
747         if (obj->eventLogging)
748             pluginLog(instance, "mouseUp at (%d, %d)", LOWORD(event->lParam), HIWORD(event->lParam));
749         break;
750     case WM_SETFOCUS:
751         if (obj->eventLogging)
752             pluginLog(instance, "getFocusEvent");
753         break;
754     case WM_KILLFOCUS:
755         if (obj->eventLogging)
756             pluginLog(instance, "loseFocusEvent");
757         break;
758     }
759     return 0;
760 }
761 #endif // XP_WIN
762
763 int16_t NPP_HandleEvent(NPP instance, void *event)
764 {
765     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
766
767     if (obj->pluginTest->NPP_HandleEvent(event) == 1)
768         return 1;
769
770 #ifdef XP_MACOSX
771 #ifndef NP_NO_CARBON
772     if (obj->eventModel == NPEventModelCarbon)
773         return handleEventCarbon(instance, obj, static_cast<EventRecord*>(event));
774 #endif
775
776     assert(obj->eventModel == NPEventModelCocoa);
777     return handleEventCocoa(instance, obj, static_cast<NPCocoaEvent*>(event));
778 #elif defined(MOZ_X11)
779     return handleEventX11(instance, obj, static_cast<XEvent*>(event));
780 #elif defined(XP_WIN)
781     return handleEventWin(instance, obj, static_cast<NPEvent*>(event));
782 #else
783     // FIXME: Implement for other platforms.
784     return 0;
785 #endif // XP_MACOSX
786 }
787
788 void NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData)
789 {
790     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
791     if (obj->pluginTest->NPP_URLNotify(url, reason, notifyData))
792         return;
793
794     if (obj->onURLNotify)
795          executeScript(obj, obj->onURLNotify);
796
797     handleCallback(obj, url, reason, notifyData);
798 }
799
800 void NPP_URLRedirectNotify(NPP instance, const char *url, int32_t status, void *notifyData)
801 {
802     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
803     obj->pluginTest->NPP_URLRedirectNotify(url, status, notifyData);
804 }
805
806 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
807 {
808 #if defined(XP_UNIX)
809     if (variable == NPPVpluginNameString) {
810         *((char **)value) = const_cast<char*>("WebKit Test PlugIn");
811         return NPERR_NO_ERROR;
812     }
813     if (variable == NPPVpluginDescriptionString) {
814         *((char **)value) = const_cast<char*>("Simple Netscape┬« plug-in that handles test content for WebKit");
815         return NPERR_NO_ERROR;
816     }
817 #endif
818
819 #if defined(MOZ_X11)
820     if (variable == NPPVpluginNeedsXEmbed) {
821         *((NPBool *)value) = TRUE;
822         return NPERR_NO_ERROR;
823     }
824 #endif
825
826     if (!instance)
827         return NPERR_GENERIC_ERROR;
828     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
829
830     // First, check if the PluginTest object supports getting this value.
831     if (obj->pluginTest->NPP_GetValue(variable, value) == NPERR_NO_ERROR)
832         return NPERR_NO_ERROR;
833
834     if (variable == NPPVpluginScriptableNPObject) {
835         void **v = (void **)value;
836         // Return value is expected to be retained
837         browser->retainobject((NPObject *)obj);
838         *v = obj;
839         return NPERR_NO_ERROR;
840     }
841     
842 #ifdef XP_MACOSX
843     if (variable == NPPVpluginCoreAnimationLayer) {
844         if (!obj->coreAnimationLayer)
845             return NPERR_GENERIC_ERROR;
846         
847         void **v = (void **)value;
848         *v = (void*)CFRetain(obj->coreAnimationLayer);
849         return NPERR_NO_ERROR;
850     }
851 #endif
852
853     return NPERR_GENERIC_ERROR;
854 }
855
856 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
857 {
858     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
859     return obj->pluginTest->NPP_SetValue(variable, value);
860 }
861
862 #if defined(XP_UNIX)
863 extern "C"
864 const char* NP_GetMIMEDescription(void)
865 {
866     return "application/x-webkit-test-netscape:testnetscape:test netscape content;image/png:png:PNG image";
867 }
868
869 extern "C"
870 NPError NP_GetValue(NPP instance, NPPVariable variable, void* value)
871 {
872     return NPP_GetValue(instance, variable, value);
873 }
874 #endif