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