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