WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebKit2/WebProcess/Plugins/Netscape/NetscapeBrowserFuncs.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,740 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "NetscapeBrowserFuncs.h"
+
+#include "NPRuntimeUtilities.h"
+#include "NetscapePlugin.h"
+#include "NotImplemented.h"
+#include <WebCore/HTTPHeaderMap.h>
+#include <WebCore/IdentifierRep.h>
+#include <WebCore/SharedBuffer.h>
+#include <utility>
+
+using namespace WebCore;
+using namespace std;
+
+namespace WebKit {
+
+static bool startsWithBlankLine(const char* bytes, unsigned length)
+{
+    return length > 0 && bytes[0] == '\n';
+}
+
+static int locationAfterFirstBlankLine(const char* bytes, unsigned length)
+{
+    for (unsigned i = 0; i < length - 4; i++) {
+        // Support for Acrobat. It sends "\n\n".
+        if (bytes[i] == '\n' && bytes[i + 1] == '\n')
+            return i + 2;
+        
+        // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
+        if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
+            i += 2;
+            if (i == 2)
+                return i;
+
+            if (bytes[i] == '\n') {
+                // Support for Director. It sends "\r\n\n" (3880387).
+                return i + 1;
+            }
+
+            if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
+                // Support for Flash. It sends "\r\n\r\n" (3758113).
+                return i + 2;
+            }
+        }
+    }
+
+    return -1;
+}
+
+static const char* findEndOfLine(const char* bytes, unsigned length)
+{
+    // According to the HTTP specification EOL is defined as
+    // a CRLF pair. Unfortunately, some servers will use LF
+    // instead. Worse yet, some servers will use a combination
+    // of both (e.g. <header>CRLFLF<body>), so findEOL needs
+    // to be more forgiving. It will now accept CRLF, LF or
+    // CR.
+    //
+    // It returns 0 if EOLF is not found or it will return
+    // a pointer to the first terminating character.
+    for (unsigned i = 0; i < length; i++) {
+        if (bytes[i] == '\n')
+            return bytes + i;
+        if (bytes[i] == '\r') {
+            // Check to see if spanning buffer bounds
+            // (CRLF is across reads). If so, wait for
+            // next read.
+            if (i + 1 == length)
+                break;
+
+            return bytes + i;
+        }
+    }
+
+    return 0;
+}
+
+static String capitalizeRFC822HeaderFieldName(const String& name)
+{
+    bool capitalizeCharacter = true;
+    String result;
+
+    for (unsigned i = 0; i < name.length(); i++) {
+        UChar c;
+
+        if (capitalizeCharacter && name[i] >= 'a' && name[i] <= 'z')
+            c = toASCIIUpper(name[i]);
+        else if (!capitalizeCharacter && name[i] >= 'A' && name[i] <= 'Z')
+            c = toASCIILower(name[i]);
+        else
+            c = name[i];
+
+        if (name[i] == '-')
+            capitalizeCharacter = true;
+        else
+            capitalizeCharacter = false;
+
+        result.append(c);
+    }
+
+    return result;
+}
+
+static HTTPHeaderMap parseRFC822HeaderFields(const char* bytes, unsigned length)
+{
+    String lastHeaderKey;
+    HTTPHeaderMap headerFields;
+
+    // Loop over lines until we're past the header, or we can't find any more end-of-lines
+    while (const char* endOfLine = findEndOfLine(bytes, length)) {
+        const char* line = bytes;
+        int lineLength = endOfLine - bytes;
+
+        // Move bytes to the character after the terminator as returned by findEndOfLine.
+        bytes = endOfLine + 1;
+        if ((*endOfLine == '\r') && (*bytes == '\n'))
+            bytes++; // Safe since findEndOfLine won't return a spanning CRLF.
+
+        length -= (bytes - line);
+        if (!lineLength) {
+            // Blank line; we're at the end of the header
+            break;
+        }
+
+        if (*line == ' ' || *line == '\t') {
+            // Continuation of the previous header
+            if (lastHeaderKey.isNull()) {
+                // malformed header; ignore it and continue
+                continue;
+            } 
+            
+            // Merge the continuation of the previous header
+            String currentValue = headerFields.get(lastHeaderKey);
+            String newValue(line, lineLength);
+            
+            headerFields.set(lastHeaderKey, currentValue + newValue);
+        } else {
+            // Brand new header
+            const char* colon = line;
+            while (*colon != ':' && colon != endOfLine)
+                colon++;
+
+            if (colon == endOfLine) {
+                // malformed header; ignore it and continue
+                continue;
+            }
+
+            lastHeaderKey = capitalizeRFC822HeaderFieldName(String(line, colon - line));
+            String value;
+            
+            for (colon++; colon != endOfLine; colon++) {
+                if (*colon != ' ' && *colon != '\t')
+                    break;
+            }
+            if (colon == endOfLine)
+                value = "";
+            else
+                value = String(colon, endOfLine - colon);
+            
+            String oldValue = headerFields.get(lastHeaderKey);
+            if (!oldValue.isNull()) {
+                String tmp = oldValue;
+                tmp += ", ";
+                tmp += value;
+                value = tmp;
+            }
+            
+            headerFields.set(lastHeaderKey, value);
+        }
+    }
+
+    return headerFields;
+}
+    
+static NPError parsePostBuffer(bool isFile, const char *buffer, uint32_t length, bool parseHeaders, HTTPHeaderMap& headerFields, Vector<char>& bodyData)
+{
+    RefPtr<SharedBuffer> fileContents;
+    const char* postBuffer = 0;
+    uint32_t postBufferSize = 0;
+
+    if (isFile) {
+        fileContents = SharedBuffer::createWithContentsOfFile(String::fromUTF8(buffer));
+        if (!fileContents)
+            return NPERR_FILE_NOT_FOUND;
+
+        postBuffer = fileContents->data();
+        postBufferSize = fileContents->size();
+
+        // FIXME: The NPAPI spec states that the file should be deleted here.
+    } else {
+        postBuffer = buffer;
+        postBufferSize = length;
+    }
+
+    if (parseHeaders) {
+        if (startsWithBlankLine(postBuffer, postBufferSize)) {
+            postBuffer++;
+            postBufferSize--;
+        } else {
+            int location = locationAfterFirstBlankLine(postBuffer, postBufferSize);
+            if (location != -1) {
+                // If the blank line is somewhere in the middle of the buffer, everything before is the header
+                headerFields = parseRFC822HeaderFields(postBuffer, location);
+                unsigned dataLength = postBufferSize - location;
+                
+                // Sometimes plugins like to set Content-Length themselves when they post,
+                // but WebFoundation does not like that. So we will remove the header
+                // and instead truncate the data to the requested length.
+                String contentLength = headerFields.get("Content-Length");
+                
+                if (!contentLength.isNull())
+                    dataLength = min(contentLength.toInt(), (int)dataLength);
+                headerFields.remove("Content-Length");
+                
+                postBuffer += location;
+                postBufferSize = dataLength;
+                
+            }
+        }
+    }
+
+    ASSERT(bodyData.isEmpty());
+    bodyData.append(postBuffer, postBufferSize);
+
+    return NPERR_NO_ERROR;
+}
+
+static String makeURLString(const char* url)
+{
+    String urlString(url);
+    
+    // Strip return characters.
+    urlString.replace('\r', "");
+    urlString.replace('\n', "");
+
+    return urlString;
+}
+
+static NPError NPN_GetURL(NPP npp, const char* url, const char* target)
+{
+    if (!url)
+        return NPERR_GENERIC_ERROR;
+    
+    RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+    plugin->loadURL("GET", makeURLString(url), target, HTTPHeaderMap(), Vector<char>(), false, 0);
+    
+    return NPERR_GENERIC_ERROR;
+}
+
+static NPError NPN_PostURL(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file)
+{
+    HTTPHeaderMap headerFields;
+    Vector<char> postData;
+    
+    // NPN_PostURL only allows headers if the post buffer points to a file.
+    bool parseHeaders = file;
+
+    NPError error = parsePostBuffer(file, buf, len, parseHeaders, headerFields, postData);
+    if (error != NPERR_NO_ERROR)
+        return error;
+
+    RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+    plugin->loadURL("POST", makeURLString(url), target, headerFields, postData, false, 0);
+    return NPERR_NO_ERROR;
+}
+
+static NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
+{
+    notImplemented();
+    return NPERR_GENERIC_ERROR;
+}
+
+static NPError NPN_NewStream(NPP instance, NPMIMEType type, const char* target, NPStream** stream)
+{
+    notImplemented();
+    return NPERR_GENERIC_ERROR;
+}
+    
+static int32_t NPN_Write(NPP instance, NPStream* stream, int32_t len, void* buffer)
+{
+    notImplemented();    
+    return -1;
+}
+    
+static NPError NPN_DestroyStream(NPP npp, NPStream* stream, NPReason reason)
+{
+    RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+    
+    return plugin->destroyStream(stream, reason);
+}
+
+static void NPN_Status(NPP instance, const char* message)
+{
+    notImplemented();
+}
+    
+static const char* NPN_UserAgent(NPP npp)
+{
+    if (!npp)
+        return 0;
+    
+    RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+    return plugin->userAgent();
+}
+
+static void* NPN_MemAlloc(uint32_t size)
+{
+    // We could use fastMalloc here, but there might be plug-ins that mix NPN_MemAlloc/NPN_MemFree with malloc and free,
+    // so having them be equivalent seems like a good idea.
+    return malloc(size);
+}
+
+static void NPN_MemFree(void* ptr)
+{
+    // We could use fastFree here, but there might be plug-ins that mix NPN_MemAlloc/NPN_MemFree with malloc and free,
+    // so having them be equivalent seems like a good idea.
+    free(ptr);
+}
+
+static uint32_t NPN_MemFlush(uint32_t size)
+{
+    return 0;
+}
+
+static void NPN_ReloadPlugins(NPBool reloadPages)
+{
+    notImplemented();
+}
+
+static JRIEnv* NPN_GetJavaEnv(void)
+{
+    notImplemented();
+    return 0;
+}
+
+static jref NPN_GetJavaPeer(NPP instance)
+{
+    notImplemented();
+    return 0;
+}
+
+static NPError NPN_GetURLNotify(NPP npp, const char* url, const char* target, void* notifyData)
+{
+    if (!url)
+        return NPERR_GENERIC_ERROR;
+
+    RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+    plugin->loadURL("GET", makeURLString(url), target, HTTPHeaderMap(), Vector<char>(), true, notifyData);
+    
+    return NPERR_NO_ERROR;
+}
+
+static NPError NPN_PostURLNotify(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData)
+{
+    HTTPHeaderMap headerFields;
+    Vector<char> postData;
+    NPError error = parsePostBuffer(file, buf, len, true, headerFields, postData);
+    if (error != NPERR_NO_ERROR)
+        return error;
+
+    RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+    plugin->loadURL("POST", makeURLString(url), target, headerFields, postData, true, notifyData);
+    return NPERR_NO_ERROR;
+}
+
+static NPError NPN_GetValue(NPP npp, NPNVariable variable, void *value)
+{
+    switch (variable) {
+        case NPNVWindowNPObject: {
+            RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+            NPObject* windowNPObject = plugin->windowScriptNPObject();
+            *(NPObject**)value = windowNPObject;
+            break;
+        }
+        case NPNVPluginElementNPObject: {
+            RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+
+            NPObject* pluginElementNPObject = plugin->pluginElementNPObject();
+            *(NPObject**)value = pluginElementNPObject;
+            break;
+        }
+#if PLATFORM(MAC)
+        case NPNVsupportsCoreGraphicsBool:
+            // Always claim to support the Core Graphics drawing model.
+            *(NPBool *)value = true;
+            break;
+
+        case NPNVsupportsCocoaBool:
+            // Always claim to support the Cocoa event model.
+            *(NPBool *)value = true;
+            break;
+#endif
+        default:
+            notImplemented();
+            return NPERR_GENERIC_ERROR;
+    }
+
+    return NPERR_NO_ERROR;
+}
+
+static NPError NPN_SetValue(NPP npp, NPPVariable variable, void *value)
+{
+    switch (variable) {
+#if PLATFORM(MAC)
+        case NPPVpluginDrawingModel: {
+            RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+            
+            NPDrawingModel drawingModel = static_cast<NPDrawingModel>(reinterpret_cast<uintptr_t>(value));
+            return plugin->setDrawingModel(drawingModel);
+        }
+
+        case NPPVpluginEventModel: {
+            RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+            
+            NPEventModel eventModel = static_cast<NPEventModel>(reinterpret_cast<uintptr_t>(value));
+            return plugin->setEventModel(eventModel);
+        }
+#endif
+
+        default:
+            notImplemented();
+            return NPERR_GENERIC_ERROR;
+    }
+    
+    return NPERR_NO_ERROR;
+}
+
+static void NPN_InvalidateRect(NPP npp, NPRect* invalidRect)
+{
+    RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+    plugin->invalidate(invalidRect);
+}
+
+static void NPN_InvalidateRegion(NPP npp, NPRegion invalidRegion)
+{
+    // FIXME: We could at least figure out the bounding rectangle of the invalid region.
+    RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
+    plugin->invalidate(0);
+}
+
+static void NPN_ForceRedraw(NPP instance)
+{
+    notImplemented();
+}
+
+static NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name)
+{
+    return static_cast<NPIdentifier>(IdentifierRep::get(name));
+}
+    
+static void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers)
+{
+    ASSERT(names);
+    ASSERT(identifiers);
+
+    if (!names || !identifiers)
+        return;
+
+    for (int32_t i = 0; i < nameCount; ++i)
+        identifiers[i] = NPN_GetStringIdentifier(names[i]);
+}
+
+static NPIdentifier NPN_GetIntIdentifier(int32_t intid)
+{
+    return static_cast<NPIdentifier>(IdentifierRep::get(intid));
+}
+
+static bool NPN_IdentifierIsString(NPIdentifier identifier)
+{
+    return static_cast<IdentifierRep*>(identifier)->isString();
+}
+
+static NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier)
+{
+    const char* string = static_cast<IdentifierRep*>(identifier)->string();
+    if (!string)
+        return 0;
+
+    uint32_t stringLength = strlen(string);
+    char* utf8String = static_cast<char*>(NPN_MemAlloc(stringLength + 1));
+    memcpy(utf8String, string, stringLength);
+    utf8String[stringLength] = '\0';
+    
+    return utf8String;
+}
+
+static int32_t NPN_IntFromIdentifier(NPIdentifier identifier)
+{
+    return static_cast<IdentifierRep*>(identifier)->number();
+}
+
+static NPObject* NPN_CreateObject(NPP npp, NPClass *npClass)
+{
+    return createNPObject(npp, npClass);
+}
+
+static NPObject *NPN_RetainObject(NPObject *npObject)
+{
+    retainNPObject(npObject);
+    return npObject;
+}
+
+static void NPN_ReleaseObject(NPObject *npObject)
+{
+    releaseNPObject(npObject);
+}
+
+static bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
+{
+    notImplemented();
+    return false;
+}
+
+static bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result)
+{
+    notImplemented();
+    return false;
+}
+
+static bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script, NPVariant *result)
+{
+    notImplemented();
+    return false;
+}
+
+static bool NPN_GetProperty(NPP npp, NPObject *npObject, NPIdentifier propertyName, NPVariant *result)
+{
+    if (npObject->_class->hasProperty && npObject->_class->getProperty) {
+        if (npObject->_class->hasProperty(npObject, propertyName))
+            return npObject->_class->getProperty(npObject, propertyName, result);
+    }
+    
+    VOID_TO_NPVARIANT(*result);
+    return false;
+}
+
+static bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value)
+{
+    notImplemented();
+    return false;
+}
+
+static bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName)
+{
+    notImplemented();
+    return false;
+}
+
+static bool NPN_HasProperty(NPP npp, NPObject *npObject, NPIdentifier propertyName)
+{
+    if (npObject->_class->hasProperty)
+        return npObject->_class->hasProperty(npObject, propertyName);
+
+    return false;
+}
+
+static bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName)
+{
+    notImplemented();
+    return false;
+}
+
+static void NPN_ReleaseVariantValue(NPVariant *variant)
+{
+    releaseNPVariantValue(variant);
+}
+
+static void NPN_SetException(NPObject *npobj, const NPUTF8 *message)
+{
+    notImplemented();
+}
+
+static void NPN_PushPopupsEnabledState(NPP instance, NPBool enabled)
+{
+    notImplemented();
+}
+    
+static void NPN_PopPopupsEnabledState(NPP instance)
+{
+    notImplemented();
+}
+    
+static bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count)
+{
+    notImplemented();
+    return false;
+}
+
+static void NPN_PluginThreadAsyncCall(NPP instance, void (*func) (void *), void *userData)
+{
+    notImplemented();
+}
+
+static bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result)
+{
+    notImplemented();
+    return false;
+}
+
+static NPError NPN_GetValueForURL(NPP instance, NPNURLVariable variable, const char *url, char **value, uint32_t *len)
+{
+    notImplemented();
+    return NPERR_GENERIC_ERROR;
+}
+
+static NPError NPN_SetValueForURL(NPP instance, NPNURLVariable variable, const char *url, const char *value, uint32_t len)
+{
+    notImplemented();
+    return NPERR_GENERIC_ERROR;
+}
+
+static NPError NPN_GetAuthenticationInfo(NPP instance, const char *protocol, const char *host, int32_t port, const char *scheme, 
+                                         const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen)
+{
+    notImplemented();
+    return NPERR_GENERIC_ERROR;
+}
+
+static uint32_t NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID))
+{
+    notImplemented();
+    return NPERR_GENERIC_ERROR;
+}
+
+static void NPN_UnscheduleTimer(NPP instance, uint32_t timerID)
+{
+    notImplemented();
+}
+
+static NPError NPN_PopUpContextMenu(NPP instance, NPMenu* menu)
+{
+    notImplemented();
+    return NPERR_GENERIC_ERROR;
+}
+
+static NPBool NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace)
+{
+    notImplemented();
+    return false;
+}
+
+static void initializeBrowserFuncs(NPNetscapeFuncs &netscapeFuncs)
+{
+    netscapeFuncs.size = sizeof(NPNetscapeFuncs);
+    netscapeFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+    
+    netscapeFuncs.geturl = NPN_GetURL;
+    netscapeFuncs.posturl = NPN_PostURL;
+    netscapeFuncs.requestread = NPN_RequestRead;
+    netscapeFuncs.newstream = NPN_NewStream;
+    netscapeFuncs.write = NPN_Write;
+    netscapeFuncs.destroystream = NPN_DestroyStream;
+    netscapeFuncs.status = NPN_Status;
+    netscapeFuncs.uagent = NPN_UserAgent;
+    netscapeFuncs.memalloc = NPN_MemAlloc;
+    netscapeFuncs.memfree = NPN_MemFree;
+    netscapeFuncs.memflush = NPN_MemFlush;
+    netscapeFuncs.reloadplugins = NPN_ReloadPlugins;
+    netscapeFuncs.getJavaEnv = NPN_GetJavaEnv;
+    netscapeFuncs.getJavaPeer = NPN_GetJavaPeer;
+    netscapeFuncs.geturlnotify = NPN_GetURLNotify;
+    netscapeFuncs.posturlnotify = NPN_PostURLNotify;
+    netscapeFuncs.getvalue = NPN_GetValue;
+    netscapeFuncs.setvalue = NPN_SetValue;
+    netscapeFuncs.invalidaterect = NPN_InvalidateRect;
+    netscapeFuncs.invalidateregion = NPN_InvalidateRegion;
+    netscapeFuncs.forceredraw = NPN_ForceRedraw;
+    
+    netscapeFuncs.getstringidentifier = NPN_GetStringIdentifier;
+    netscapeFuncs.getstringidentifiers = NPN_GetStringIdentifiers;
+    netscapeFuncs.getintidentifier = NPN_GetIntIdentifier;
+    netscapeFuncs.identifierisstring = NPN_IdentifierIsString;
+    netscapeFuncs.utf8fromidentifier = NPN_UTF8FromIdentifier;
+    netscapeFuncs.intfromidentifier = NPN_IntFromIdentifier;
+    netscapeFuncs.createobject = NPN_CreateObject;
+    netscapeFuncs.retainobject = NPN_RetainObject;
+    netscapeFuncs.releaseobject = NPN_ReleaseObject;
+    netscapeFuncs.invoke = NPN_Invoke;
+    netscapeFuncs.invokeDefault = NPN_InvokeDefault;
+    netscapeFuncs.evaluate = NPN_Evaluate;
+    netscapeFuncs.getproperty = NPN_GetProperty;
+    netscapeFuncs.setproperty = NPN_SetProperty;
+    netscapeFuncs.removeproperty = NPN_RemoveProperty;
+    netscapeFuncs.hasproperty = NPN_HasProperty;
+    netscapeFuncs.hasmethod = NPN_HasMethod;
+    netscapeFuncs.releasevariantvalue = NPN_ReleaseVariantValue;
+    netscapeFuncs.setexception = NPN_SetException;
+    netscapeFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
+    netscapeFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState;
+    netscapeFuncs.enumerate = NPN_Enumerate;
+    netscapeFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
+    netscapeFuncs.construct = NPN_Construct;
+    netscapeFuncs.getvalueforurl = NPN_GetValueForURL;
+    netscapeFuncs.setvalueforurl = NPN_SetValueForURL;
+    netscapeFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo;
+    netscapeFuncs.scheduletimer = NPN_ScheduleTimer;
+    netscapeFuncs.unscheduletimer = NPN_UnscheduleTimer;
+    netscapeFuncs.popupcontextmenu = NPN_PopUpContextMenu;
+    netscapeFuncs.convertpoint = NPN_ConvertPoint;
+}
+    
+NPNetscapeFuncs* netscapeBrowserFuncs()
+{
+    static NPNetscapeFuncs netscapeFuncs;
+    static bool initialized = false;
+    
+    if (!initialized) {
+        initializeBrowserFuncs(netscapeFuncs);
+        initialized = true;
+    }
+
+    return &netscapeFuncs;
+}
+
+} // namespace WebKit