| 1 | /* |
| 2 | * Copyright (C) 2010-2018 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. AND ITS CONTRIBUTORS ``AS IS'' |
| 14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| 15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| 23 | * THE POSSIBILITY OF SUCH DAMAGE. |
| 24 | */ |
| 25 | |
| 26 | #include "config.h" |
| 27 | #include "NetscapeBrowserFuncs.h" |
| 28 | |
| 29 | #if ENABLE(NETSCAPE_PLUGIN_API) |
| 30 | |
| 31 | #include "NPRuntimeUtilities.h" |
| 32 | #include "NetscapePlugin.h" |
| 33 | #include "PluginController.h" |
| 34 | #include <WebCore/HTTPHeaderMap.h> |
| 35 | #include <WebCore/HTTPHeaderNames.h> |
| 36 | #include <WebCore/IdentifierRep.h> |
| 37 | #include <WebCore/NotImplemented.h> |
| 38 | #include <WebCore/ProtectionSpace.h> |
| 39 | #include <WebCore/SharedBuffer.h> |
| 40 | #include <memory> |
| 41 | #include <utility> |
| 42 | #include <wtf/text/StringBuilder.h> |
| 43 | |
| 44 | #if PLATFORM(COCOA) |
| 45 | #include <wtf/MachSendRight.h> |
| 46 | #endif |
| 47 | |
| 48 | #if PLATFORM(X11) |
| 49 | #include <WebCore/PlatformDisplayX11.h> |
| 50 | #endif |
| 51 | |
| 52 | namespace WebKit { |
| 53 | using namespace WebCore; |
| 54 | |
| 55 | // Helper class for delaying destruction of a plug-in. |
| 56 | class PluginDestructionProtector { |
| 57 | public: |
| 58 | explicit PluginDestructionProtector(NetscapePlugin* plugin) |
| 59 | { |
| 60 | if (plugin) |
| 61 | m_protector = std::make_unique<PluginController::PluginDestructionProtector>(static_cast<Plugin*>(plugin)->controller()); |
| 62 | } |
| 63 | |
| 64 | private: |
| 65 | std::unique_ptr<PluginController::PluginDestructionProtector> m_protector; |
| 66 | }; |
| 67 | |
| 68 | static bool startsWithBlankLine(const char* bytes, unsigned length) |
| 69 | { |
| 70 | return length > 0 && bytes[0] == '\n'; |
| 71 | } |
| 72 | |
| 73 | static int locationAfterFirstBlankLine(const char* bytes, unsigned length) |
| 74 | { |
| 75 | for (unsigned i = 0; i < length - 4; i++) { |
| 76 | // Support for Acrobat. It sends "\n\n". |
| 77 | if (bytes[i] == '\n' && bytes[i + 1] == '\n') |
| 78 | return i + 2; |
| 79 | |
| 80 | // Returns the position after 2 CRLF's or 1 CRLF if it is the first line. |
| 81 | if (bytes[i] == '\r' && bytes[i + 1] == '\n') { |
| 82 | i += 2; |
| 83 | if (i == 2) |
| 84 | return i; |
| 85 | |
| 86 | if (bytes[i] == '\n') { |
| 87 | // Support for Director. It sends "\r\n\n" (3880387). |
| 88 | return i + 1; |
| 89 | } |
| 90 | |
| 91 | if (bytes[i] == '\r' && bytes[i + 1] == '\n') { |
| 92 | // Support for Flash. It sends "\r\n\r\n" (3758113). |
| 93 | return i + 2; |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | return -1; |
| 99 | } |
| 100 | |
| 101 | static const char* findEndOfLine(const char* bytes, unsigned length) |
| 102 | { |
| 103 | // According to the HTTP specification EOL is defined as |
| 104 | // a CRLF pair. Unfortunately, some servers will use LF |
| 105 | // instead. Worse yet, some servers will use a combination |
| 106 | // of both (e.g. <header>CRLFLF<body>), so findEOL needs |
| 107 | // to be more forgiving. It will now accept CRLF, LF or |
| 108 | // CR. |
| 109 | // |
| 110 | // It returns 0 if EOLF is not found or it will return |
| 111 | // a pointer to the first terminating character. |
| 112 | for (unsigned i = 0; i < length; i++) { |
| 113 | if (bytes[i] == '\n') |
| 114 | return bytes + i; |
| 115 | if (bytes[i] == '\r') { |
| 116 | // Check to see if spanning buffer bounds |
| 117 | // (CRLF is across reads). If so, wait for |
| 118 | // next read. |
| 119 | if (i + 1 == length) |
| 120 | break; |
| 121 | |
| 122 | return bytes + i; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | return 0; |
| 127 | } |
| 128 | |
| 129 | static String (const String& name) |
| 130 | { |
| 131 | bool capitalizeCharacter = true; |
| 132 | StringBuilder result; |
| 133 | for (unsigned i = 0; i < name.length(); i++) { |
| 134 | result.append(capitalizeCharacter ? toASCIIUpper(name[i]) : toASCIILower(name[i])); |
| 135 | if (name[i] == '-') |
| 136 | capitalizeCharacter = true; |
| 137 | else |
| 138 | capitalizeCharacter = false; |
| 139 | } |
| 140 | return result.toString(); |
| 141 | } |
| 142 | |
| 143 | static HTTPHeaderMap (const char* bytes, unsigned length) |
| 144 | { |
| 145 | String ; |
| 146 | HTTPHeaderMap ; |
| 147 | |
| 148 | // Loop over lines until we're past the header, or we can't find any more end-of-lines |
| 149 | while (const char* endOfLine = findEndOfLine(bytes, length)) { |
| 150 | const char* line = bytes; |
| 151 | int lineLength = endOfLine - bytes; |
| 152 | |
| 153 | // Move bytes to the character after the terminator as returned by findEndOfLine. |
| 154 | bytes = endOfLine + 1; |
| 155 | if ((*endOfLine == '\r') && (*bytes == '\n')) |
| 156 | bytes++; // Safe since findEndOfLine won't return a spanning CRLF. |
| 157 | |
| 158 | length -= (bytes - line); |
| 159 | if (!lineLength) { |
| 160 | // Blank line; we're at the end of the header |
| 161 | break; |
| 162 | } |
| 163 | |
| 164 | if (*line == ' ' || *line == '\t') { |
| 165 | // Continuation of the previous header |
| 166 | if (lastHeaderKey.isNull()) { |
| 167 | // malformed header; ignore it and continue |
| 168 | continue; |
| 169 | } |
| 170 | |
| 171 | // Merge the continuation of the previous header |
| 172 | String currentValue = headerFields.get(lastHeaderKey); |
| 173 | String newValue(line, lineLength); |
| 174 | |
| 175 | headerFields.set(lastHeaderKey, currentValue + newValue); |
| 176 | } else { |
| 177 | // Brand new header |
| 178 | const char* colon = line; |
| 179 | while (*colon != ':' && colon != endOfLine) |
| 180 | colon++; |
| 181 | |
| 182 | if (colon == endOfLine) { |
| 183 | // malformed header; ignore it and continue |
| 184 | continue; |
| 185 | } |
| 186 | |
| 187 | lastHeaderKey = capitalizeRFC822HeaderFieldName(String(line, colon - line)); |
| 188 | String value; |
| 189 | |
| 190 | for (colon++; colon != endOfLine; colon++) { |
| 191 | if (*colon != ' ' && *colon != '\t') |
| 192 | break; |
| 193 | } |
| 194 | if (colon == endOfLine) |
| 195 | value = emptyString(); |
| 196 | else |
| 197 | value = String(colon, endOfLine - colon); |
| 198 | |
| 199 | String oldValue = headerFields.get(lastHeaderKey); |
| 200 | if (!oldValue.isNull()) |
| 201 | value = oldValue + ", " + value; |
| 202 | |
| 203 | headerFields.set(lastHeaderKey, value); |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | return headerFields; |
| 208 | } |
| 209 | |
| 210 | static NPError (bool isFile, const char *buffer, uint32_t length, bool , HTTPHeaderMap& , Vector<uint8_t>& bodyData) |
| 211 | { |
| 212 | RefPtr<SharedBuffer> fileContents; |
| 213 | const char* postBuffer = 0; |
| 214 | uint32_t postBufferSize = 0; |
| 215 | |
| 216 | if (isFile) { |
| 217 | fileContents = SharedBuffer::createWithContentsOfFile(String::fromUTF8(buffer)); |
| 218 | if (!fileContents) |
| 219 | return NPERR_FILE_NOT_FOUND; |
| 220 | |
| 221 | postBuffer = fileContents->data(); |
| 222 | postBufferSize = fileContents->size(); |
| 223 | |
| 224 | // FIXME: The NPAPI spec states that the file should be deleted here. |
| 225 | } else { |
| 226 | postBuffer = buffer; |
| 227 | postBufferSize = length; |
| 228 | } |
| 229 | |
| 230 | if (parseHeaders) { |
| 231 | if (startsWithBlankLine(postBuffer, postBufferSize)) { |
| 232 | postBuffer++; |
| 233 | postBufferSize--; |
| 234 | } else { |
| 235 | int location = locationAfterFirstBlankLine(postBuffer, postBufferSize); |
| 236 | if (location != -1) { |
| 237 | // If the blank line is somewhere in the middle of the buffer, everything before is the header |
| 238 | headerFields = parseRFC822HeaderFields(postBuffer, location); |
| 239 | unsigned dataLength = postBufferSize - location; |
| 240 | |
| 241 | // Sometimes plugins like to set Content-Length themselves when they post, |
| 242 | // but WebFoundation does not like that. So we will remove the header |
| 243 | // and instead truncate the data to the requested length. |
| 244 | String contentLength = headerFields.get(HTTPHeaderName::ContentLength); |
| 245 | |
| 246 | if (!contentLength.isNull()) |
| 247 | dataLength = std::min(contentLength.toInt(), (int)dataLength); |
| 248 | headerFields.remove(HTTPHeaderName::ContentLength); |
| 249 | |
| 250 | postBuffer += location; |
| 251 | postBufferSize = dataLength; |
| 252 | } |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | ASSERT(bodyData.isEmpty()); |
| 257 | bodyData.append(postBuffer, postBufferSize); |
| 258 | |
| 259 | return NPERR_NO_ERROR; |
| 260 | } |
| 261 | |
| 262 | static String makeURLString(const char* url) |
| 263 | { |
| 264 | String urlString(url); |
| 265 | |
| 266 | // Strip return characters. |
| 267 | urlString.replaceWithLiteral('\r', "" ); |
| 268 | urlString.replaceWithLiteral('\n', "" ); |
| 269 | |
| 270 | return urlString; |
| 271 | } |
| 272 | |
| 273 | static NPError NPN_GetURL(NPP npp, const char* url, const char* target) |
| 274 | { |
| 275 | if (!url) |
| 276 | return NPERR_GENERIC_ERROR; |
| 277 | |
| 278 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 279 | plugin->loadURL("GET" , makeURLString(url), target, HTTPHeaderMap(), Vector<uint8_t>(), false, 0); |
| 280 | |
| 281 | return NPERR_GENERIC_ERROR; |
| 282 | } |
| 283 | |
| 284 | static NPError NPN_PostURL(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file) |
| 285 | { |
| 286 | HTTPHeaderMap ; |
| 287 | Vector<uint8_t> postData; |
| 288 | |
| 289 | // NPN_PostURL only allows headers if the post buffer points to a file. |
| 290 | bool = file; |
| 291 | |
| 292 | NPError error = parsePostBuffer(file, buf, len, parseHeaders, headerFields, postData); |
| 293 | if (error != NPERR_NO_ERROR) |
| 294 | return error; |
| 295 | |
| 296 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 297 | plugin->loadURL("POST" , makeURLString(url), target, WTFMove(headerFields), postData, false, 0); |
| 298 | return NPERR_NO_ERROR; |
| 299 | } |
| 300 | |
| 301 | static NPError NPN_RequestRead(NPStream*, NPByteRange*) |
| 302 | { |
| 303 | notImplemented(); |
| 304 | return NPERR_GENERIC_ERROR; |
| 305 | } |
| 306 | |
| 307 | static NPError NPN_NewStream(NPP, NPMIMEType, const char*, NPStream**) |
| 308 | { |
| 309 | notImplemented(); |
| 310 | return NPERR_GENERIC_ERROR; |
| 311 | } |
| 312 | |
| 313 | static int32_t NPN_Write(NPP, NPStream*, int32_t, void*) |
| 314 | { |
| 315 | notImplemented(); |
| 316 | return -1; |
| 317 | } |
| 318 | |
| 319 | static NPError NPN_DestroyStream(NPP npp, NPStream* stream, NPReason reason) |
| 320 | { |
| 321 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 322 | |
| 323 | return plugin->destroyStream(stream, reason); |
| 324 | } |
| 325 | |
| 326 | static void NPN_Status(NPP npp, const char* message) |
| 327 | { |
| 328 | String statusbarText; |
| 329 | if (!message) |
| 330 | statusbarText = emptyString(); |
| 331 | else |
| 332 | statusbarText = String::fromUTF8WithLatin1Fallback(message, strlen(message)); |
| 333 | |
| 334 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 335 | plugin->setStatusbarText(statusbarText); |
| 336 | } |
| 337 | |
| 338 | static const char* NPN_UserAgent(NPP npp) |
| 339 | { |
| 340 | return NetscapePlugin::userAgent(npp); |
| 341 | } |
| 342 | |
| 343 | static void* NPN_MemAlloc(uint32_t size) |
| 344 | { |
| 345 | return npnMemAlloc(size); |
| 346 | } |
| 347 | |
| 348 | static void NPN_MemFree(void* ptr) |
| 349 | { |
| 350 | npnMemFree(ptr); |
| 351 | } |
| 352 | |
| 353 | static uint32_t NPN_MemFlush(uint32_t) |
| 354 | { |
| 355 | return 0; |
| 356 | } |
| 357 | |
| 358 | static void NPN_ReloadPlugins(NPBool) |
| 359 | { |
| 360 | notImplemented(); |
| 361 | } |
| 362 | |
| 363 | static JRIEnv* NPN_GetJavaEnv(void) |
| 364 | { |
| 365 | notImplemented(); |
| 366 | return 0; |
| 367 | } |
| 368 | |
| 369 | static jref NPN_GetJavaPeer(NPP) |
| 370 | { |
| 371 | notImplemented(); |
| 372 | return 0; |
| 373 | } |
| 374 | |
| 375 | static NPError NPN_GetURLNotify(NPP npp, const char* url, const char* target, void* notifyData) |
| 376 | { |
| 377 | if (!url) |
| 378 | return NPERR_GENERIC_ERROR; |
| 379 | |
| 380 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 381 | plugin->loadURL("GET" , makeURLString(url), target, HTTPHeaderMap(), Vector<uint8_t>(), true, notifyData); |
| 382 | |
| 383 | return NPERR_NO_ERROR; |
| 384 | } |
| 385 | |
| 386 | static NPError NPN_PostURLNotify(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData) |
| 387 | { |
| 388 | HTTPHeaderMap ; |
| 389 | Vector<uint8_t> postData; |
| 390 | NPError error = parsePostBuffer(file, buf, len, true, headerFields, postData); |
| 391 | if (error != NPERR_NO_ERROR) |
| 392 | return error; |
| 393 | |
| 394 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 395 | plugin->loadURL("POST" , makeURLString(url), target, headerFields, postData, true, notifyData); |
| 396 | return NPERR_NO_ERROR; |
| 397 | } |
| 398 | |
| 399 | #if PLATFORM(COCOA) |
| 400 | // Whether the browser supports compositing of Core Animation plug-ins. |
| 401 | static const unsigned WKNVSupportsCompositingCoreAnimationPluginsBool = 74656; |
| 402 | |
| 403 | // Whether the browser expects a non-retained Core Animation layer. |
| 404 | static const unsigned WKNVExpectsNonretainedLayer = 74657; |
| 405 | |
| 406 | // 74658 and 74659 are no longer implemented. |
| 407 | |
| 408 | #endif |
| 409 | |
| 410 | static NPError NPN_GetValue(NPP npp, NPNVariable variable, void *value) |
| 411 | { |
| 412 | switch (static_cast<unsigned>(variable)) { |
| 413 | case NPNVWindowNPObject: { |
| 414 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 415 | PluginDestructionProtector protector(plugin.get()); |
| 416 | |
| 417 | NPObject* windowNPObject = plugin->windowScriptNPObject(); |
| 418 | if (!windowNPObject) |
| 419 | return NPERR_GENERIC_ERROR; |
| 420 | |
| 421 | *(NPObject**)value = windowNPObject; |
| 422 | break; |
| 423 | } |
| 424 | case NPNVPluginElementNPObject: { |
| 425 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 426 | PluginDestructionProtector protector(plugin.get()); |
| 427 | |
| 428 | NPObject* pluginElementNPObject = plugin->pluginElementNPObject(); |
| 429 | *(NPObject**)value = pluginElementNPObject; |
| 430 | break; |
| 431 | } |
| 432 | case NPNVprivateModeBool: { |
| 433 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 434 | |
| 435 | *(NPBool*)value = plugin->isPrivateBrowsingEnabled(); |
| 436 | break; |
| 437 | } |
| 438 | |
| 439 | case NPNVmuteAudioBool: { |
| 440 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 441 | *(NPBool*)value = plugin->isMuted(); |
| 442 | break; |
| 443 | } |
| 444 | #if PLATFORM(COCOA) |
| 445 | case NPNVsupportsCoreGraphicsBool: |
| 446 | // Always claim to support the Core Graphics drawing model. |
| 447 | *(NPBool*)value = true; |
| 448 | break; |
| 449 | |
| 450 | case WKNVSupportsCompositingCoreAnimationPluginsBool: |
| 451 | case NPNVsupportsCoreAnimationBool: { |
| 452 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 453 | |
| 454 | *(NPBool*)value = plugin->isAcceleratedCompositingEnabled(); |
| 455 | break; |
| 456 | } |
| 457 | case NPNVcontentsScaleFactor: { |
| 458 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 459 | |
| 460 | *(double*)value = plugin->contentsScaleFactor(); |
| 461 | break; |
| 462 | } |
| 463 | case NPNVsupportsCocoaBool: |
| 464 | // Always claim to support the Cocoa event model. |
| 465 | *(NPBool*)value = true; |
| 466 | break; |
| 467 | |
| 468 | case NPNVsupportsUpdatedCocoaTextInputBool: { |
| 469 | // The plug-in is asking whether we support the updated Cocoa text input model. |
| 470 | // If we haven't yet delivered a key down event to the plug-in, we can opt into the updated |
| 471 | // model and say that we support it. Otherwise, we'll just fall back and say that we don't support it. |
| 472 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 473 | |
| 474 | bool supportsUpdatedTextInput = !plugin->hasHandledAKeyDownEvent(); |
| 475 | if (supportsUpdatedTextInput) |
| 476 | plugin->setPluginWantsLegacyCocoaTextInput(false); |
| 477 | |
| 478 | *reinterpret_cast<NPBool*>(value) = supportsUpdatedTextInput; |
| 479 | break; |
| 480 | } |
| 481 | |
| 482 | case WKNVCALayerRenderServerPort: { |
| 483 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 484 | |
| 485 | *(mach_port_t*)value = plugin->compositingRenderServerPort().sendRight(); |
| 486 | break; |
| 487 | } |
| 488 | |
| 489 | case WKNVExpectsNonretainedLayer: { |
| 490 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 491 | |
| 492 | // Asking for this will make us expect a non-retained layer from the plug-in. |
| 493 | plugin->setPluginReturnsNonretainedLayer(true); |
| 494 | *(NPBool*)value = true; |
| 495 | break; |
| 496 | } |
| 497 | #elif PLATFORM(X11) |
| 498 | case NPNVxDisplay: { |
| 499 | if (!npp) |
| 500 | return NPERR_GENERIC_ERROR; |
| 501 | auto& display = PlatformDisplay::sharedDisplay(); |
| 502 | if (display.type() != PlatformDisplay::Type::X11) |
| 503 | return NPERR_GENERIC_ERROR; |
| 504 | *reinterpret_cast<Display**>(value) = downcast<PlatformDisplayX11>(display).native(); |
| 505 | break; |
| 506 | } |
| 507 | case NPNVSupportsXEmbedBool: |
| 508 | *static_cast<NPBool*>(value) = PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11; |
| 509 | break; |
| 510 | case NPNVSupportsWindowless: |
| 511 | *static_cast<NPBool*>(value) = true; |
| 512 | break; |
| 513 | |
| 514 | case NPNVToolkit: { |
| 515 | // Gtk based plugins need to be assured about the toolkit version. |
| 516 | const uint32_t expectedGtkToolKitVersion = 2; |
| 517 | *reinterpret_cast<uint32_t*>(value) = expectedGtkToolKitVersion; |
| 518 | break; |
| 519 | } |
| 520 | |
| 521 | // TODO: implement NPNVnetscapeWindow once we want to support windowed plugins. |
| 522 | #endif |
| 523 | default: |
| 524 | notImplemented(); |
| 525 | return NPERR_GENERIC_ERROR; |
| 526 | } |
| 527 | |
| 528 | return NPERR_NO_ERROR; |
| 529 | } |
| 530 | |
| 531 | static NPError NPN_SetValue(NPP npp, NPPVariable variable, void *value) |
| 532 | { |
| 533 | switch (variable) { |
| 534 | #if PLATFORM(COCOA) |
| 535 | case NPPVpluginDrawingModel: { |
| 536 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 537 | |
| 538 | NPDrawingModel drawingModel = static_cast<NPDrawingModel>(reinterpret_cast<uintptr_t>(value)); |
| 539 | return plugin->setDrawingModel(drawingModel); |
| 540 | } |
| 541 | |
| 542 | case NPPVpluginEventModel: { |
| 543 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 544 | |
| 545 | NPEventModel eventModel = static_cast<NPEventModel>(reinterpret_cast<uintptr_t>(value)); |
| 546 | return plugin->setEventModel(eventModel); |
| 547 | } |
| 548 | #endif |
| 549 | |
| 550 | case NPPVpluginWindowBool: { |
| 551 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 552 | plugin->setIsWindowed(value); |
| 553 | return NPERR_NO_ERROR; |
| 554 | } |
| 555 | |
| 556 | case NPPVpluginTransparentBool: { |
| 557 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 558 | plugin->setIsTransparent(value); |
| 559 | return NPERR_NO_ERROR; |
| 560 | } |
| 561 | |
| 562 | case NPPVpluginIsPlayingAudio: { |
| 563 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 564 | plugin->setIsPlayingAudio(value); |
| 565 | return NPERR_NO_ERROR; |
| 566 | } |
| 567 | |
| 568 | default: |
| 569 | notImplemented(); |
| 570 | return NPERR_GENERIC_ERROR; |
| 571 | } |
| 572 | } |
| 573 | |
| 574 | static void NPN_InvalidateRect(NPP npp, NPRect* invalidRect) |
| 575 | { |
| 576 | #if PLUGIN_ARCHITECTURE(UNIX) |
| 577 | // NSPluginWrapper, a plugin wrapper binary that allows running 32-bit plugins |
| 578 | // on 64-bit architectures typically used in X11, will sometimes give us a null NPP here. |
| 579 | if (!npp) |
| 580 | return; |
| 581 | #endif |
| 582 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 583 | plugin->invalidate(invalidRect); |
| 584 | } |
| 585 | |
| 586 | static void NPN_InvalidateRegion(NPP npp, NPRegion) |
| 587 | { |
| 588 | // FIXME: We could at least figure out the bounding rectangle of the invalid region. |
| 589 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 590 | plugin->invalidate(0); |
| 591 | } |
| 592 | |
| 593 | static void NPN_ForceRedraw(NPP) |
| 594 | { |
| 595 | notImplemented(); |
| 596 | } |
| 597 | |
| 598 | static NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name) |
| 599 | { |
| 600 | return static_cast<NPIdentifier>(IdentifierRep::get(name)); |
| 601 | } |
| 602 | |
| 603 | static void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers) |
| 604 | { |
| 605 | ASSERT(names); |
| 606 | ASSERT(identifiers); |
| 607 | |
| 608 | if (!names || !identifiers) |
| 609 | return; |
| 610 | |
| 611 | for (int32_t i = 0; i < nameCount; ++i) |
| 612 | identifiers[i] = NPN_GetStringIdentifier(names[i]); |
| 613 | } |
| 614 | |
| 615 | static NPIdentifier NPN_GetIntIdentifier(int32_t intid) |
| 616 | { |
| 617 | return static_cast<NPIdentifier>(IdentifierRep::get(intid)); |
| 618 | } |
| 619 | |
| 620 | static bool NPN_IdentifierIsString(NPIdentifier identifier) |
| 621 | { |
| 622 | return static_cast<IdentifierRep*>(identifier)->isString(); |
| 623 | } |
| 624 | |
| 625 | static NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier) |
| 626 | { |
| 627 | const char* string = static_cast<IdentifierRep*>(identifier)->string(); |
| 628 | if (!string) |
| 629 | return 0; |
| 630 | |
| 631 | uint32_t stringLength = strlen(string); |
| 632 | char* utf8String = npnMemNewArray<char>(stringLength + 1); |
| 633 | memcpy(utf8String, string, stringLength); |
| 634 | utf8String[stringLength] = '\0'; |
| 635 | |
| 636 | return utf8String; |
| 637 | } |
| 638 | |
| 639 | static int32_t NPN_IntFromIdentifier(NPIdentifier identifier) |
| 640 | { |
| 641 | return static_cast<IdentifierRep*>(identifier)->number(); |
| 642 | } |
| 643 | |
| 644 | static NPObject* NPN_CreateObject(NPP npp, NPClass *npClass) |
| 645 | { |
| 646 | return createNPObject(npp, npClass); |
| 647 | } |
| 648 | |
| 649 | static NPObject *NPN_RetainObject(NPObject *npObject) |
| 650 | { |
| 651 | retainNPObject(npObject); |
| 652 | return npObject; |
| 653 | } |
| 654 | |
| 655 | static void NPN_ReleaseObject(NPObject *npObject) |
| 656 | { |
| 657 | releaseNPObject(npObject); |
| 658 | } |
| 659 | |
| 660 | static bool NPN_Invoke(NPP npp, NPObject *npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
| 661 | { |
| 662 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 663 | PluginDestructionProtector protector(plugin.get()); |
| 664 | |
| 665 | if (npObject->_class->invoke) |
| 666 | return npObject->_class->invoke(npObject, methodName, arguments, argumentCount, result); |
| 667 | |
| 668 | return false; |
| 669 | } |
| 670 | |
| 671 | static bool NPN_InvokeDefault(NPP npp, NPObject *npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
| 672 | { |
| 673 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 674 | PluginDestructionProtector protector(plugin.get()); |
| 675 | |
| 676 | if (npObject->_class->invokeDefault) |
| 677 | return npObject->_class->invokeDefault(npObject, arguments, argumentCount, result); |
| 678 | |
| 679 | return false; |
| 680 | } |
| 681 | |
| 682 | static bool NPN_Evaluate(NPP npp, NPObject *npObject, NPString *script, NPVariant* result) |
| 683 | { |
| 684 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 685 | PluginDestructionProtector protector(plugin.get()); |
| 686 | |
| 687 | String scriptString = String::fromUTF8WithLatin1Fallback(script->UTF8Characters, script->UTF8Length); |
| 688 | |
| 689 | return plugin->evaluate(npObject, scriptString, result); |
| 690 | } |
| 691 | |
| 692 | static bool NPN_GetProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName, NPVariant* result) |
| 693 | { |
| 694 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 695 | PluginDestructionProtector protector(plugin.get()); |
| 696 | |
| 697 | if (npObject->_class->getProperty) |
| 698 | return npObject->_class->getProperty(npObject, propertyName, result); |
| 699 | |
| 700 | return false; |
| 701 | } |
| 702 | |
| 703 | static bool NPN_SetProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName, const NPVariant* value) |
| 704 | { |
| 705 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 706 | PluginDestructionProtector protector(plugin.get()); |
| 707 | |
| 708 | if (npObject->_class->setProperty) |
| 709 | return npObject->_class->setProperty(npObject, propertyName, value); |
| 710 | |
| 711 | return false; |
| 712 | } |
| 713 | |
| 714 | static bool NPN_RemoveProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName) |
| 715 | { |
| 716 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 717 | PluginDestructionProtector protector(plugin.get()); |
| 718 | |
| 719 | if (npObject->_class->removeProperty) |
| 720 | return npObject->_class->removeProperty(npObject, propertyName); |
| 721 | |
| 722 | return false; |
| 723 | } |
| 724 | |
| 725 | static bool NPN_HasProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName) |
| 726 | { |
| 727 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 728 | PluginDestructionProtector protector(plugin.get()); |
| 729 | |
| 730 | if (npObject->_class->hasProperty) |
| 731 | return npObject->_class->hasProperty(npObject, propertyName); |
| 732 | |
| 733 | return false; |
| 734 | } |
| 735 | |
| 736 | static bool NPN_HasMethod(NPP npp, NPObject* npObject, NPIdentifier methodName) |
| 737 | { |
| 738 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 739 | PluginDestructionProtector protector(plugin.get()); |
| 740 | |
| 741 | if (npObject->_class->hasMethod) |
| 742 | return npObject->_class->hasMethod(npObject, methodName); |
| 743 | |
| 744 | return false; |
| 745 | } |
| 746 | |
| 747 | static void NPN_ReleaseVariantValue(NPVariant* variant) |
| 748 | { |
| 749 | releaseNPVariantValue(variant); |
| 750 | } |
| 751 | |
| 752 | static void NPN_SetException(NPObject*, const NPUTF8* message) |
| 753 | { |
| 754 | NetscapePlugin::setException(message); |
| 755 | } |
| 756 | |
| 757 | static void (NPP npp, NPBool enabled) |
| 758 | { |
| 759 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 760 | plugin->pushPopupsEnabledState(enabled); |
| 761 | } |
| 762 | |
| 763 | static void (NPP npp) |
| 764 | { |
| 765 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 766 | plugin->popPopupsEnabledState(); |
| 767 | } |
| 768 | |
| 769 | static bool NPN_Enumerate(NPP npp, NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount) |
| 770 | { |
| 771 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 772 | PluginDestructionProtector protector(plugin.get()); |
| 773 | |
| 774 | if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npObject->_class) && npObject->_class->enumerate) |
| 775 | return npObject->_class->enumerate(npObject, identifiers, identifierCount); |
| 776 | |
| 777 | return false; |
| 778 | } |
| 779 | |
| 780 | static void NPN_PluginThreadAsyncCall(NPP npp, void (*function)(void*), void* userData) |
| 781 | { |
| 782 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 783 | |
| 784 | plugin->pluginThreadAsyncCall(function, userData); |
| 785 | } |
| 786 | |
| 787 | static bool NPN_Construct(NPP npp, NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) |
| 788 | { |
| 789 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 790 | PluginDestructionProtector protector(plugin.get()); |
| 791 | |
| 792 | if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npObject->_class) && npObject->_class->construct) |
| 793 | return npObject->_class->construct(npObject, arguments, argumentCount, result); |
| 794 | |
| 795 | return false; |
| 796 | } |
| 797 | |
| 798 | static NPError copyCString(const CString& string, char** value, uint32_t* len) |
| 799 | { |
| 800 | ASSERT(!string.isNull()); |
| 801 | ASSERT(value); |
| 802 | ASSERT(len); |
| 803 | |
| 804 | *value = npnMemNewArray<char>(string.length()); |
| 805 | if (!*value) |
| 806 | return NPERR_GENERIC_ERROR; |
| 807 | |
| 808 | memcpy(*value, string.data(), string.length()); |
| 809 | *len = string.length(); |
| 810 | return NPERR_NO_ERROR; |
| 811 | } |
| 812 | |
| 813 | static NPError NPN_GetValueForURL(NPP npp, NPNURLVariable variable, const char* url, char** value, uint32_t* len) |
| 814 | { |
| 815 | if (!value || !len) |
| 816 | return NPERR_GENERIC_ERROR; |
| 817 | |
| 818 | switch (variable) { |
| 819 | case NPNURLVCookie: { |
| 820 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 821 | PluginDestructionProtector protector(plugin.get()); |
| 822 | |
| 823 | String cookies = plugin->cookiesForURL(makeURLString(url)); |
| 824 | if (cookies.isNull()) |
| 825 | return NPERR_GENERIC_ERROR; |
| 826 | |
| 827 | return copyCString(cookies.utf8(), value, len); |
| 828 | } |
| 829 | |
| 830 | case NPNURLVProxy: { |
| 831 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 832 | PluginDestructionProtector protector(plugin.get()); |
| 833 | |
| 834 | String proxies = plugin->proxiesForURL(makeURLString(url)); |
| 835 | if (proxies.isNull()) |
| 836 | return NPERR_GENERIC_ERROR; |
| 837 | |
| 838 | return copyCString(proxies.utf8(), value, len); |
| 839 | } |
| 840 | default: |
| 841 | notImplemented(); |
| 842 | return NPERR_GENERIC_ERROR; |
| 843 | } |
| 844 | } |
| 845 | |
| 846 | static NPError NPN_SetValueForURL(NPP npp, NPNURLVariable variable, const char* url, const char* value, uint32_t len) |
| 847 | { |
| 848 | switch (variable) { |
| 849 | case NPNURLVCookie: { |
| 850 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 851 | PluginDestructionProtector protector(plugin.get()); |
| 852 | |
| 853 | plugin->setCookiesForURL(makeURLString(url), String(value, len)); |
| 854 | return NPERR_NO_ERROR; |
| 855 | } |
| 856 | |
| 857 | case NPNURLVProxy: |
| 858 | // Can't set the proxy for a URL. |
| 859 | return NPERR_GENERIC_ERROR; |
| 860 | |
| 861 | default: |
| 862 | notImplemented(); |
| 863 | return NPERR_GENERIC_ERROR; |
| 864 | } |
| 865 | } |
| 866 | |
| 867 | static bool initializeProtectionSpace(const char* protocol, const char* host, int port, const char* scheme, const char* realm, ProtectionSpace& protectionSpace) |
| 868 | { |
| 869 | ProtectionSpaceServerType serverType; |
| 870 | if (equalLettersIgnoringASCIICase(protocol, "http" )) |
| 871 | serverType = ProtectionSpaceServerHTTP; |
| 872 | else if (equalLettersIgnoringASCIICase(protocol, "https" )) |
| 873 | serverType = ProtectionSpaceServerHTTPS; |
| 874 | else { |
| 875 | // We only care about http and https. |
| 876 | return false; |
| 877 | } |
| 878 | |
| 879 | ProtectionSpaceAuthenticationScheme authenticationScheme = ProtectionSpaceAuthenticationSchemeDefault; |
| 880 | if (serverType == ProtectionSpaceServerHTTP) { |
| 881 | if (equalLettersIgnoringASCIICase(scheme, "basic" )) |
| 882 | authenticationScheme = ProtectionSpaceAuthenticationSchemeHTTPBasic; |
| 883 | else if (equalLettersIgnoringASCIICase(scheme, "digest" )) |
| 884 | authenticationScheme = ProtectionSpaceAuthenticationSchemeHTTPDigest; |
| 885 | } |
| 886 | |
| 887 | protectionSpace = ProtectionSpace(host, port, serverType, realm, authenticationScheme); |
| 888 | return true; |
| 889 | } |
| 890 | |
| 891 | static NPError NPN_GetAuthenticationInfo(NPP npp, const char* protocol, const char* host, int32_t port, const char* scheme, |
| 892 | const char* realm, char** username, uint32_t* usernameLength, char** password, uint32_t* passwordLength) |
| 893 | { |
| 894 | if (!protocol || !host || !scheme || !realm || !username || !usernameLength || !password || !passwordLength) |
| 895 | return NPERR_GENERIC_ERROR; |
| 896 | |
| 897 | ProtectionSpace protectionSpace; |
| 898 | if (!initializeProtectionSpace(protocol, host, port, scheme, realm, protectionSpace)) |
| 899 | return NPERR_GENERIC_ERROR; |
| 900 | |
| 901 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 902 | String usernameString; |
| 903 | String passwordString; |
| 904 | if (!plugin->getAuthenticationInfo(protectionSpace, usernameString, passwordString)) |
| 905 | return NPERR_GENERIC_ERROR; |
| 906 | |
| 907 | NPError result = copyCString(usernameString.utf8(), username, usernameLength); |
| 908 | if (result != NPERR_NO_ERROR) |
| 909 | return result; |
| 910 | |
| 911 | result = copyCString(passwordString.utf8(), password, passwordLength); |
| 912 | if (result != NPERR_NO_ERROR) { |
| 913 | npnMemFree(*username); |
| 914 | return result; |
| 915 | } |
| 916 | |
| 917 | return NPERR_NO_ERROR; |
| 918 | } |
| 919 | |
| 920 | static uint32_t NPN_ScheduleTimer(NPP npp, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID)) |
| 921 | { |
| 922 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 923 | |
| 924 | return plugin->scheduleTimer(interval, repeat, timerFunc); |
| 925 | } |
| 926 | |
| 927 | static void NPN_UnscheduleTimer(NPP npp, uint32_t timerID) |
| 928 | { |
| 929 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 930 | |
| 931 | plugin->unscheduleTimer(timerID); |
| 932 | } |
| 933 | |
| 934 | #if PLATFORM(COCOA) |
| 935 | static NPError NPN_PopUpContextMenu(NPP npp, NPMenu* menu) |
| 936 | { |
| 937 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 938 | |
| 939 | return plugin->popUpContextMenu(menu); |
| 940 | } |
| 941 | |
| 942 | static NPBool NPN_ConvertPoint(NPP npp, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double* destX, double* destY, NPCoordinateSpace destSpace) |
| 943 | { |
| 944 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 945 | |
| 946 | double destinationX; |
| 947 | double destinationY; |
| 948 | |
| 949 | bool returnValue = plugin->convertPoint(sourceX, sourceY, sourceSpace, destinationX, destinationY, destSpace); |
| 950 | |
| 951 | if (destX) |
| 952 | *destX = destinationX; |
| 953 | if (destY) |
| 954 | *destY = destinationY; |
| 955 | |
| 956 | return returnValue; |
| 957 | } |
| 958 | #endif |
| 959 | |
| 960 | static void NPN_URLRedirectResponse(NPP npp, void* notifyData, NPBool allow) |
| 961 | { |
| 962 | RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp); |
| 963 | |
| 964 | plugin->urlRedirectResponse(notifyData, allow); |
| 965 | } |
| 966 | |
| 967 | static void initializeBrowserFuncs(NPNetscapeFuncs &netscapeFuncs) |
| 968 | { |
| 969 | netscapeFuncs.size = sizeof(NPNetscapeFuncs); |
| 970 | netscapeFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; |
| 971 | |
| 972 | netscapeFuncs.geturl = NPN_GetURL; |
| 973 | netscapeFuncs.posturl = NPN_PostURL; |
| 974 | netscapeFuncs.requestread = NPN_RequestRead; |
| 975 | netscapeFuncs.newstream = NPN_NewStream; |
| 976 | netscapeFuncs.write = NPN_Write; |
| 977 | netscapeFuncs.destroystream = NPN_DestroyStream; |
| 978 | netscapeFuncs.status = NPN_Status; |
| 979 | netscapeFuncs.uagent = NPN_UserAgent; |
| 980 | netscapeFuncs.memalloc = NPN_MemAlloc; |
| 981 | netscapeFuncs.memfree = NPN_MemFree; |
| 982 | netscapeFuncs.memflush = NPN_MemFlush; |
| 983 | netscapeFuncs.reloadplugins = NPN_ReloadPlugins; |
| 984 | netscapeFuncs.getJavaEnv = NPN_GetJavaEnv; |
| 985 | netscapeFuncs.getJavaPeer = NPN_GetJavaPeer; |
| 986 | netscapeFuncs.geturlnotify = NPN_GetURLNotify; |
| 987 | netscapeFuncs.posturlnotify = NPN_PostURLNotify; |
| 988 | netscapeFuncs.getvalue = NPN_GetValue; |
| 989 | netscapeFuncs.setvalue = NPN_SetValue; |
| 990 | netscapeFuncs.invalidaterect = NPN_InvalidateRect; |
| 991 | netscapeFuncs.invalidateregion = NPN_InvalidateRegion; |
| 992 | netscapeFuncs.forceredraw = NPN_ForceRedraw; |
| 993 | |
| 994 | netscapeFuncs.getstringidentifier = NPN_GetStringIdentifier; |
| 995 | netscapeFuncs.getstringidentifiers = NPN_GetStringIdentifiers; |
| 996 | netscapeFuncs.getintidentifier = NPN_GetIntIdentifier; |
| 997 | netscapeFuncs.identifierisstring = NPN_IdentifierIsString; |
| 998 | netscapeFuncs.utf8fromidentifier = NPN_UTF8FromIdentifier; |
| 999 | netscapeFuncs.intfromidentifier = NPN_IntFromIdentifier; |
| 1000 | netscapeFuncs.createobject = NPN_CreateObject; |
| 1001 | netscapeFuncs.retainobject = NPN_RetainObject; |
| 1002 | netscapeFuncs.releaseobject = NPN_ReleaseObject; |
| 1003 | netscapeFuncs.invoke = NPN_Invoke; |
| 1004 | netscapeFuncs.invokeDefault = NPN_InvokeDefault; |
| 1005 | netscapeFuncs.evaluate = NPN_Evaluate; |
| 1006 | netscapeFuncs.getproperty = NPN_GetProperty; |
| 1007 | netscapeFuncs.setproperty = NPN_SetProperty; |
| 1008 | netscapeFuncs.removeproperty = NPN_RemoveProperty; |
| 1009 | netscapeFuncs.hasproperty = NPN_HasProperty; |
| 1010 | netscapeFuncs.hasmethod = NPN_HasMethod; |
| 1011 | netscapeFuncs.releasevariantvalue = NPN_ReleaseVariantValue; |
| 1012 | netscapeFuncs.setexception = NPN_SetException; |
| 1013 | netscapeFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState; |
| 1014 | netscapeFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState; |
| 1015 | netscapeFuncs.enumerate = NPN_Enumerate; |
| 1016 | netscapeFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall; |
| 1017 | netscapeFuncs.construct = NPN_Construct; |
| 1018 | netscapeFuncs.getvalueforurl = NPN_GetValueForURL; |
| 1019 | netscapeFuncs.setvalueforurl = NPN_SetValueForURL; |
| 1020 | netscapeFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo; |
| 1021 | netscapeFuncs.scheduletimer = NPN_ScheduleTimer; |
| 1022 | netscapeFuncs.unscheduletimer = NPN_UnscheduleTimer; |
| 1023 | #if PLATFORM(COCOA) |
| 1024 | netscapeFuncs.popupcontextmenu = NPN_PopUpContextMenu; |
| 1025 | netscapeFuncs.convertpoint = NPN_ConvertPoint; |
| 1026 | #else |
| 1027 | netscapeFuncs.popupcontextmenu = 0; |
| 1028 | netscapeFuncs.convertpoint = 0; |
| 1029 | #endif |
| 1030 | netscapeFuncs.urlredirectresponse = NPN_URLRedirectResponse; |
| 1031 | } |
| 1032 | |
| 1033 | NPNetscapeFuncs* netscapeBrowserFuncs() |
| 1034 | { |
| 1035 | static NPNetscapeFuncs netscapeFuncs; |
| 1036 | static bool initialized = false; |
| 1037 | |
| 1038 | if (!initialized) { |
| 1039 | initializeBrowserFuncs(netscapeFuncs); |
| 1040 | initialized = true; |
| 1041 | } |
| 1042 | |
| 1043 | return &netscapeFuncs; |
| 1044 | } |
| 1045 | |
| 1046 | } // namespace WebKit |
| 1047 | |
| 1048 | #endif // ENABLE(NETSCAPE_PLUGIN_API) |
| 1049 | |