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