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