diff options
Diffstat (limited to 'WebCore/plugins/android')
-rw-r--r-- | WebCore/plugins/android/PlugInInfoStoreAndroid.cpp | 85 | ||||
-rw-r--r-- | WebCore/plugins/android/PluginDatabaseAndroid.cpp | 347 | ||||
-rw-r--r-- | WebCore/plugins/android/PluginDatabaseAndroid.h | 91 | ||||
-rw-r--r-- | WebCore/plugins/android/PluginDebug.h | 44 | ||||
-rw-r--r-- | WebCore/plugins/android/PluginPackageAndroid.cpp | 504 | ||||
-rw-r--r-- | WebCore/plugins/android/PluginPackageAndroid.h | 152 | ||||
-rw-r--r-- | WebCore/plugins/android/PluginViewAndroid.cpp | 567 | ||||
-rw-r--r-- | WebCore/plugins/android/PluginViewAndroid.h | 176 | ||||
-rw-r--r-- | WebCore/plugins/android/npapi.cpp | 200 | ||||
-rw-r--r-- | WebCore/plugins/android/npfunctions.h | 201 |
10 files changed, 2367 insertions, 0 deletions
diff --git a/WebCore/plugins/android/PlugInInfoStoreAndroid.cpp b/WebCore/plugins/android/PlugInInfoStoreAndroid.cpp new file mode 100644 index 0000000..780e5f0 --- /dev/null +++ b/WebCore/plugins/android/PlugInInfoStoreAndroid.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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 "config.h" +#include "PluginInfoStore.h" +#include "PluginDatabaseAndroid.h" +#include "PluginPackageAndroid.h" + +namespace WebCore { + +PluginInfo* PluginInfoStore::createPluginInfoForPluginAtIndex(unsigned i) +{ + PluginDatabaseAndroid *db = PluginDatabaseAndroid::installedPlugins(); + PluginInfo* info = new PluginInfo; + PluginPackageAndroid* package = db->plugins()[i]; + + info->name = package->name(); + info->file = package->fileName(); + info->desc = package->description(); + + const MIMEToDescriptionsMap& mimeToDescriptions = package->mimeToDescriptions(); + MIMEToDescriptionsMap::const_iterator end = mimeToDescriptions.end(); + for (MIMEToDescriptionsMap::const_iterator it = mimeToDescriptions.begin(); it != end; ++it) { + MimeClassInfo* mime = new MimeClassInfo; + info->mimes.append(mime); + + mime->type = it->first; + mime->desc = it->second; + mime->plugin = info; + + Vector<String> extensions = package->mimeToExtensions().get(mime->type); + + for (unsigned i = 0; i < extensions.size(); i++) { + if (i > 0) + mime->suffixes += ","; + + mime->suffixes += extensions[i]; + } + } + + return info; +} + +unsigned PluginInfoStore::pluginCount() const +{ + return PluginDatabaseAndroid::installedPlugins()->plugins().size(); +} + +bool PluginInfoStore::supportsMIMEType(const WebCore::String& mimeType) +{ + return PluginDatabaseAndroid::installedPlugins()->isMIMETypeRegistered(mimeType); +} + +void refreshPlugins(bool reloadOpenPages) +{ + PluginDatabaseAndroid::installedPlugins()->refresh(); + + if (reloadOpenPages) { + // FIXME: reload open pages + } +} + +} diff --git a/WebCore/plugins/android/PluginDatabaseAndroid.cpp b/WebCore/plugins/android/PluginDatabaseAndroid.cpp new file mode 100644 index 0000000..411855c --- /dev/null +++ b/WebCore/plugins/android/PluginDatabaseAndroid.cpp @@ -0,0 +1,347 @@ +#ifdef ANDROID_PLUGINS + +/* + * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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 "config.h" +#include "PluginDatabaseAndroid.h" +#include "PluginPackageAndroid.h" +#include "PluginViewAndroid.h" +#include "Frame.h" +#include <sys/types.h> +#include <dirent.h> +#include <limits.h> +#include <stdlib.h> + +#include "PluginDebug.h" + +namespace WebCore { + +String PluginDatabaseAndroid::s_defaultPluginsPath; + +PluginDatabaseAndroid* PluginDatabaseAndroid::installedPlugins() +{ + static PluginDatabaseAndroid* plugins = 0; + + if (!plugins) { + plugins = new PluginDatabaseAndroid; + plugins->refresh(); + } + + return plugins; +} + +void PluginDatabaseAndroid::setDefaultPluginsPath(const String& path) +{ + // Change the default plugins path and rescan. + if(path != s_defaultPluginsPath) { + s_defaultPluginsPath = path; + installedPlugins()->refresh(); + } +} + +PluginDatabaseAndroid::PluginDatabaseAndroid() + : m_pluginsPaths() + , m_plugins() +{ +} + +PluginDatabaseAndroid::~PluginDatabaseAndroid() +{ +} + +void PluginDatabaseAndroid::addExtraPluginPath(const String& path) +{ + m_pluginsPaths.append(path); + refresh(); +} + +bool PluginDatabaseAndroid::addPluginFile(const String& path) +{ + PLUGIN_LOG("Adding plugin \"%s\"\n", path.utf8().data()); + + // Check if the plugin is already loaded. + PluginPackageAndroid* plugin = findPluginByPath(path); + + // Stat the file to check we can access it. + struct stat statbuf; + if(stat(path.utf8().data(), &statbuf)) { + // Stat failed. We can't access this file. + PLUGIN_LOG("Couldn't stat library \"%s\": %s\n", + path.utf8().data(), strerror(errno)); + // Well, can't load this plugin, then. + if(plugin) { + // If we previous succeeded loading it, unload it now. + removePlugin(plugin); + } + // Failed to load. + return false; + } + + // Check the modification time. + uint32 lastModified = statbuf.st_mtime; + if(plugin) { + // Compare to the currently loaded version. + if(lastModified == plugin->getLastModified()) { + // It's the same plugin. No new actions required. + return true; + } else { + // It has been modified. Unload the old version. + removePlugin(plugin); + } + } + + // If we get here, we either just unloaded an old plugin, or this + // is a new one. Create a new package. + PluginPackageAndroid* package = + PluginPackageAndroid::createPackage(path, lastModified); + if(package) { + // Success, add to the vector of plugins. + PLUGIN_LOG("Successfully added plugin \"%s\"\n", path.utf8().data()); + m_plugins.append(package); + return true; + } else { + // Failed. + return false; + } +} + +bool PluginDatabaseAndroid::addPluginsInDirectory(const String& path) +{ + // Open a directory iterator + DIR* dir_it = opendir(path.utf8().data()); + if(!dir_it) { + PLUGIN_LOG("Cannot open directory \"%s\"\n", + path.utf8().data()); + return false; + } + // Scan the directory for "*.so" and "*.so.*" files. + struct dirent* entry; + while((entry = readdir(dir_it)) != NULL) { + const char* name = entry->d_name; + // Skip current and parent directory entries. + if(!strcmp(name, ".") || !strcmp(name, "..")) + continue; + const char* so = strstr(name, ".so"); + if(so && (so[3] == 0 || so[3] == '.')) { + // Matches our pattern, add it. + addPluginFile(path + "/" + name); + } + } + closedir(dir_it); + return true; +} + +void PluginDatabaseAndroid::removePlugin(PluginPackageAndroid* plugin) +{ + // Find this plugin in the array and remove it. + for(unsigned i = 0; i < m_plugins.size(); ++i) { + if(m_plugins[i] == plugin) { + PLUGIN_LOG("Removed plugin \"%s\"\n", + plugin->path().utf8().data()); + // This will cause a reference count to decrement. When + // the plugin actually stops getting used by all + // documents, its instance will delete itself. + m_plugins.remove(i); + break; + } + } + PLUGIN_LOG("Tried to remove plugin %p which didn't exist!\n", plugin); +} + +bool PluginDatabaseAndroid::refresh() +{ + PLUGIN_LOG("PluginDatabaseAndroid::refresh()\n"); + + // Don't delete existing plugins. The directory scan will add new + // plugins and also refresh old plugins if their file is modified + // since the last check. + + // Scan each directory and add any plugins found in them. This is + // not recursive. + if(s_defaultPluginsPath.length() > 0) + addPluginsInDirectory(s_defaultPluginsPath); + for(unsigned i = 0; i < m_pluginsPaths.size(); ++i) + addPluginsInDirectory(m_pluginsPaths[i]); + + // Now stat() all plugins and remove any that we can't + // access. This handles the case of a plugin being deleted at + // runtime. + for(unsigned i = 0; i < m_plugins.size();) { + struct stat statbuf; + if(stat(m_plugins[i]->path().utf8().data(), &statbuf)) { + // It's gone away. Remove it from the list. + m_plugins.remove(i); + } else { + ++i; + } + } + + return true; +} + +Vector<PluginPackageAndroid*> PluginDatabaseAndroid::plugins() const +{ + Vector<PluginPackageAndroid*> result; + + for(PackageRefVector::const_iterator it = m_plugins.begin(); + it != m_plugins.end(); ++it) + result.append(it->get()); + + return result; +} + +bool PluginDatabaseAndroid::isMIMETypeRegistered(const String& mimeType) const +{ + // Iterate through every package + for(PackageRefVector::const_iterator it = m_plugins.begin(); + it != m_plugins.end(); ++it) { + // Check if this package has the MIME type mapped to an extension + const PluginPackageAndroid *package = it->get(); + const MIMEToExtensionsMap& mime_extension_map = + package->mimeToExtensions(); + if(mime_extension_map.find(mimeType) != mime_extension_map.end()) { + // Found it + return true; + } + } + // No package has this MIME type + return false; +} + +bool PluginDatabaseAndroid::isPluginBlacklisted(PluginPackageAndroid* plugin) +{ + // If there is ever a plugin in the wild which causes the latest + // version of Android to crash, then stick a check here for it and + // return true when matched. + return false; +} + +PluginPackageAndroid* PluginDatabaseAndroid::pluginForMIMEType( + const String& mimeType) +{ + // Todo: these data structures are not right. This is inefficient. + // Iterate through every package + for(PackageRefVector::iterator it = m_plugins.begin(); + it != m_plugins.end(); ++it) { + // Check if this package has the MIME type mapped to a description + PluginPackageAndroid *package = it->get(); + const MIMEToDescriptionsMap& mime_desc_map = + package->mimeToDescriptions(); + if(mime_desc_map.find(mimeType) != mime_desc_map.end()) { + // Found it + return package; + } + } + // No package has this MIME type + return NULL; +} + +String PluginDatabaseAndroid::MIMETypeForExtension(const String& extension) + const +{ + // Todo: these data structures are not right. This is inefficient. + // Iterate through every package + for(PackageRefVector::const_iterator it = m_plugins.begin(); + it != m_plugins.end(); ++it) { + // Check if this package has the MIME type mapped to an extension + PluginPackageAndroid *package = it->get(); + const MIMEToDescriptionsMap& mime_desc_map = + package->mimeToDescriptions(); + for(MIMEToDescriptionsMap::const_iterator map_it = + mime_desc_map.begin(); + map_it != mime_desc_map.end(); ++map_it) { + if(map_it->second == extension) { + // Found it + return map_it->first; + } + } + } + // No MIME type matches this extension + return String(""); +} + +PluginPackageAndroid* PluginDatabaseAndroid::findPlugin(const KURL& url, + String& mimeType) +{ + PluginPackageAndroid* plugin = pluginForMIMEType(mimeType); + String filename = url.string(); + + if (!plugin) { + String filename = url.lastPathComponent(); + if (!filename.endsWith("/")) { + int extensionPos = filename.reverseFind('.'); + if (extensionPos != -1) { + String extension = filename.substring(extensionPos + 1); + + mimeType = MIMETypeForExtension(extension); + if (mimeType.length()) { + plugin = pluginForMIMEType(mimeType); + } + } + } + } + // No MIME type matches this url + return plugin; +} + +PluginPackageAndroid* PluginDatabaseAndroid::findPluginByPath( + const String& path) +{ + for(PackageRefVector::iterator it = m_plugins.begin(); + it != m_plugins.end(); ++it) { + if((*it)->path() == path) + return it->get(); // Found it + } + return 0; // Not found. +} + +PluginViewAndroid* PluginDatabaseAndroid::createPluginView( + Frame* parentFrame, + const IntSize& size, + Element* element, + const KURL& url, + const Vector<String>& paramNames, + const Vector<String>& paramValues, + const String& mimeType, + bool loadManually) +{ + // if we fail to find a plugin for this MIME type, findPlugin will search for + // a plugin by the file extension and update the MIME type, so pass a mutable String + String mimeTypeCopy = mimeType; + PluginPackageAndroid* plugin = findPlugin(url, mimeTypeCopy); + + // No plugin was found, try refreshing the database and searching again + if (!plugin && refresh()) { + mimeTypeCopy = mimeType; + plugin = findPlugin(url, mimeTypeCopy); + } + + return new PluginViewAndroid(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually); +} + +} + +#endif diff --git a/WebCore/plugins/android/PluginDatabaseAndroid.h b/WebCore/plugins/android/PluginDatabaseAndroid.h new file mode 100644 index 0000000..72814e9 --- /dev/null +++ b/WebCore/plugins/android/PluginDatabaseAndroid.h @@ -0,0 +1,91 @@ +#ifdef ANDROID_PLUGINS + +/* + * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#ifndef PluginDatabaseAndroid_H +#define PluginDatabaseAndroid_H + +#include <wtf/Vector.h> + +#include "PlatformString.h" +#include "PluginPackageAndroid.h" + +namespace WebCore { + class Element; + class Frame; + class IntSize; + class KURL; + class PluginPackageAndroid; + class PluginViewAndroid; + + class PluginDatabaseAndroid { + public: + ~PluginDatabaseAndroid(); + + static PluginDatabaseAndroid* installedPlugins(); + PluginViewAndroid* createPluginView(Frame* parentFrame, + const IntSize&, + Element* element, + const KURL& url, + const Vector<String>& paramNames, + const Vector<String>& paramValues, + const String& mimeType, + bool loadManually); + + bool refresh(); + Vector<PluginPackageAndroid*> plugins() const; + bool isMIMETypeRegistered(const String& mimeType) const; + void addExtraPluginPath(const String&); + static bool isPluginBlacklisted(PluginPackageAndroid* plugin); + static void setDefaultPluginsPath(const String&); + + private: + explicit PluginDatabaseAndroid(); + + bool addPluginFile(const String& path); + bool addPluginsInDirectory(const String& path); + PluginPackageAndroid* findPlugin(const KURL& url, String& mimeType); + PluginPackageAndroid* pluginForMIMEType(const String& mimeType); + String MIMETypeForExtension(const String& extension) const; + PluginPackageAndroid* findPluginByPath(const String& path); + void removePlugin(PluginPackageAndroid* plugin); + + // List of all paths to search for plugins + Vector<String> m_pluginsPaths; + + // List of all PluginPackageAndroid instances + typedef Vector<RefPtr<PluginPackageAndroid> > PackageRefVector; + PackageRefVector m_plugins; + + // The default plugins path from Settings. + static String s_defaultPluginsPath; + }; + +} // namespace WebCore + +#endif + +#endif diff --git a/WebCore/plugins/android/PluginDebug.h b/WebCore/plugins/android/PluginDebug.h new file mode 100644 index 0000000..8adbbd7 --- /dev/null +++ b/WebCore/plugins/android/PluginDebug.h @@ -0,0 +1,44 @@ +#ifdef ANDROID_PLUGINS + +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef PLUGIN_DEBUG_H__ +#define PLUGIN_DEBUG_H__ + +// Include this file last to avoid clashes with the definition of LOG. + +#undef LOG +#define LOG_TAG "WebKit" +#include "utils/Log.h" + +// Define PLUGIN_DEBUG_LOCAL in an individual C++ file to enable for +// that file only. + +// Define PLUGIN_DEBUG_GLOBAL to 1 to turn plug-in debug for all +// Android plug-in code in this direectory. +#define PLUGIN_DEBUG_GLOBAL 0 + +#if PLUGIN_DEBUG_GLOBAL || defined(PLUGIN_DEBUG_LOCAL) +# define PLUGIN_LOG(A, B...) do { LOGI( A , ## B ); } while(0) +#else +# define PLUGIN_LOG(A, B...) do { } while(0) +#endif + +#endif // defined(PLUGIN_DEBUG_H__) + +#endif // defined(ANDROID_PLUGINS) diff --git a/WebCore/plugins/android/PluginPackageAndroid.cpp b/WebCore/plugins/android/PluginPackageAndroid.cpp new file mode 100644 index 0000000..b8dca9a --- /dev/null +++ b/WebCore/plugins/android/PluginPackageAndroid.cpp @@ -0,0 +1,504 @@ +#ifdef ANDROID_PLUGINS + +/* + * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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 "config.h" +#include "WebCoreJni.h" +#include "PluginPackageAndroid.h" +#include "PluginDatabaseAndroid.h" + +#include "Timer.h" +#include "DeprecatedString.h" +#include "PlatformString.h" +#include "CString.h" +#include "npruntime_impl.h" + +#include <dlfcn.h> +#include <errno.h> + +#include "PluginDebug.h" + +namespace WebCore { + +PluginPackageAndroid::PluginPackageAndroid(const String& path, + uint32 lastModified) + : m_path(path), + m_name(), + m_fileName(), + m_description(), + m_lastModified(lastModified), + m_pluginFuncs(), + m_mimeToDescriptions(), + m_mimeToExtensions(), + m_env(0), + m_pluginObject(0), + m_libraryHandle(NULL), + m_libraryInitialized(false), + m_NP_Initialize((NP_InitializeFuncPtr) NULL), + m_NP_Shutdown((NP_ShutdownFuncPtr) NULL), + m_NP_GetMIMEDescription((NP_GetMIMEDescriptionFuncPtr) NULL), + m_NP_GetValue((NP_GetValueFuncPtr) NULL) +{ + PLUGIN_LOG("Constructing PluginPackageAndroid\n"); + if(android::WebCoreJni::getJavaVM()->GetEnv((void**) &m_env, + JNI_VERSION_1_4) != JNI_OK) { + PLUGIN_LOG("GetEnv failed!"); + } +} + +PluginPackageAndroid::~PluginPackageAndroid() +{ + PLUGIN_LOG("Destructing PluginPackageAndroid\n"); + unload(); +} + +void PluginPackageAndroid::initializeBrowserFuncs() +{ + // Initialize the NPN function pointers that we hand over to the + // plugin. + + memset(&m_browserFuncs, 0, sizeof(m_browserFuncs)); + + m_browserFuncs.size = sizeof(m_browserFuncs); + m_browserFuncs.version = NP_VERSION_MINOR; + m_browserFuncs.geturl = NPN_GetURL; + m_browserFuncs.posturl = NPN_PostURL; + m_browserFuncs.requestread = NPN_RequestRead; + m_browserFuncs.newstream = NPN_NewStream; + m_browserFuncs.write = NPN_Write; + m_browserFuncs.destroystream = NPN_DestroyStream; + m_browserFuncs.status = NPN_Status; + m_browserFuncs.uagent = NPN_UserAgent; + m_browserFuncs.memalloc = NPN_MemAlloc; + m_browserFuncs.memfree = NPN_MemFree; + m_browserFuncs.memflush = NPN_MemFlush; + m_browserFuncs.reloadplugins = NPN_ReloadPlugins; + m_browserFuncs.geturlnotify = NPN_GetURLNotify; + m_browserFuncs.posturlnotify = NPN_PostURLNotify; + m_browserFuncs.getvalue = NPN_GetValue; + m_browserFuncs.setvalue = NPN_SetValue; + m_browserFuncs.invalidaterect = NPN_InvalidateRect; + m_browserFuncs.invalidateregion = NPN_InvalidateRegion; + m_browserFuncs.forceredraw = NPN_ForceRedraw; + m_browserFuncs.getJavaEnv = NPN_GetJavaEnv; + m_browserFuncs.getJavaPeer = NPN_GetJavaPeer; + m_browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState; + m_browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState; + m_browserFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall; + + m_browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue; + m_browserFuncs.getstringidentifier = _NPN_GetStringIdentifier; + m_browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers; + m_browserFuncs.getintidentifier = _NPN_GetIntIdentifier; + m_browserFuncs.identifierisstring = _NPN_IdentifierIsString; + m_browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier; + m_browserFuncs.intfromidentifier = _NPN_IntFromIdentifier; + m_browserFuncs.createobject = _NPN_CreateObject; + m_browserFuncs.retainobject = _NPN_RetainObject; + m_browserFuncs.releaseobject = _NPN_ReleaseObject; + m_browserFuncs.invoke = _NPN_Invoke; + m_browserFuncs.invokeDefault = _NPN_InvokeDefault; + m_browserFuncs.evaluate = _NPN_Evaluate; + m_browserFuncs.getproperty = _NPN_GetProperty; + m_browserFuncs.setproperty = _NPN_SetProperty; + m_browserFuncs.removeproperty = _NPN_RemoveProperty; + m_browserFuncs.hasproperty = _NPN_HasProperty; + m_browserFuncs.hasmethod = _NPN_HasMethod; + m_browserFuncs.setexception = _NPN_SetException; + m_browserFuncs.enumerate = _NPN_Enumerate; +} + +jobject PluginPackageAndroid::createPluginObject(const char *name, + const char *path, + const char *fileName, + const char *description) +{ + // Create a Java "class Plugin" object instance + jclass pluginClass = m_env->FindClass("android/webkit/Plugin"); + if(!pluginClass) { + PLUGIN_LOG("Couldn't find class android.webkit.Plugin\n"); + return 0; + } + // Get Plugin(String, String, String, String, Context) + jmethodID pluginConstructor = m_env->GetMethodID( + pluginClass, + "<init>", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if(!pluginConstructor) { + PLUGIN_LOG("Couldn't get android.webkit.Plugin constructor\n"); + return 0; + } + // Make Java strings of name, path, fileName, description + jstring javaName = m_env->NewStringUTF(name); + jstring javaPath = m_env->NewStringUTF(m_path.utf8().data()); + jstring javaFileName = m_env->NewStringUTF(m_fileName.utf8().data()); + jstring javaDescription = m_env->NewStringUTF(description); + // Make a plugin instance + jobject pluginObject = m_env->NewObject(pluginClass, + pluginConstructor, + javaName, + javaPath, + javaFileName, + javaDescription); + return pluginObject; +} + +jobject PluginPackageAndroid::getPluginListObject() +{ + // Get WebView.getPluginList() + jclass webViewClass = m_env->FindClass("android/webkit/WebView"); + if(!webViewClass) { + PLUGIN_LOG("Couldn't find class android.webkit.WebView\n"); + return 0; + } + jmethodID getPluginList = m_env->GetStaticMethodID( + webViewClass, + "getPluginList", + "()Landroid/webkit/PluginList;"); + if(!getPluginList) { + PLUGIN_LOG("Couldn't find android.webkit.WebView.getPluginList()\n"); + return 0; + } + // Get the PluginList instance + jobject pluginListObject = m_env->CallStaticObjectMethod(webViewClass, + getPluginList); + if(!pluginListObject) { + PLUGIN_LOG("Couldn't get PluginList object\n"); + return 0; + } + return pluginListObject; +} + +bool PluginPackageAndroid::addPluginObjectToList(jobject pluginList, + jobject plugin) +{ + // Add the Plugin object + jclass pluginListClass = m_env->FindClass("android/webkit/PluginList"); + if(!pluginListClass) { + PLUGIN_LOG("Couldn't find class android.webkit.PluginList\n"); + return false; + } + jmethodID addPlugin = m_env->GetMethodID( + pluginListClass, + "addPlugin", + "(Landroid/webkit/Plugin;)V"); + if(!addPlugin) { + PLUGIN_LOG("Couldn't find android.webkit.PluginList.addPlugin()\n"); + return false; + } + m_env->CallVoidMethod(pluginList, + addPlugin, + plugin); + return true; +} + +void PluginPackageAndroid::removePluginObjectFromList(jobject pluginList, + jobject plugin) +{ + // Remove the Plugin object + jclass pluginListClass = m_env->FindClass("android/webkit/PluginList"); + if(!pluginListClass) { + PLUGIN_LOG("Couldn't find class android.webkit.PluginList\n"); + return; + } + jmethodID removePlugin = m_env->GetMethodID( + pluginListClass, + "removePlugin", + "(Landroid/webkit/Plugin;)V"); + if(!removePlugin) { + PLUGIN_LOG("Couldn't find android.webkit.PluginList.removePlugin()\n"); + return; + } + m_env->CallVoidMethod(pluginList, + removePlugin, + plugin); +} + +bool PluginPackageAndroid::load() +{ + if(m_libraryHandle) { + PLUGIN_LOG("Plugin \"%s\" already loaded\n", m_path.utf8().data()); + return true; + } + + PLUGIN_LOG("Loading \"%s\"\n", m_path.utf8().data()); + + // Open the library + void *handle = dlopen(m_path.utf8().data(), RTLD_NOW); + if(!handle) { + PLUGIN_LOG("Couldn't load plugin library \"%s\": %s\n", + m_path.utf8().data(), dlerror()); + return false; + } + m_libraryHandle = handle; + // This object will call dlclose() and set m_libraryHandle to NULL + // when going out of scope. + DynamicLibraryCloser dlCloser(this); + + // Get the four entry points we need for Linux Netscape Plug-ins + if(!getEntryPoint("NP_Initialize", (void **) &m_NP_Initialize) || + !getEntryPoint("NP_Shutdown", (void **) &m_NP_Shutdown) || + !getEntryPoint("NP_GetMIMEDescription", + (void **) &m_NP_GetMIMEDescription) || + !getEntryPoint("NP_GetValue", (void **) &m_NP_GetValue)) { + // If any of those failed to resolve, fail the entire load + return false; + } + + // Get the plugin name and description using NP_GetValue + const char *name; + const char *description; + if(m_NP_GetValue(NULL, NPPVpluginNameString, + &name) != NPERR_NO_ERROR || + m_NP_GetValue(NULL, NPPVpluginDescriptionString, + &description) != NPERR_NO_ERROR) { + PLUGIN_LOG("Couldn't get name/description using NP_GetValue\n"); + return false; + } + + PLUGIN_LOG("Plugin name: \"%s\"\n", name); + PLUGIN_LOG("Plugin description: \"%s\"\n", description); + m_name = name; + m_description = description; + + // fileName is just the trailing part of the path + int last_slash = m_path.reverseFind('/'); + if(last_slash < 0) + m_fileName = m_path; + else + m_fileName = m_path.substring(last_slash + 1); + + // Grab the MIME description. This is in the format, e.g: + // application/x-somescriptformat:ssf:Some Script Format + const char *mime_description = m_NP_GetMIMEDescription(); + if(!initializeMIMEDescription(mime_description)) { + PLUGIN_LOG("Bad MIME description: \"%s\"\n", + mime_description); + return false; + } + + // Create a new Java Plugin object. + jobject pluginObject = createPluginObject(name, + m_path.utf8().data(), + m_fileName.utf8().data(), + description); + if(!pluginObject) { + PLUGIN_LOG("Couldn't create Java Plugin\n"); + return false; + } + + // Provide the plugin with our browser function table and grab its + // plugin table. Provide the Java environment and the Plugin which + // can be used to override the defaults if the plugin wants. + initializeBrowserFuncs(); + memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); + m_pluginFuncs.size = sizeof(m_pluginFuncs); + if(m_NP_Initialize(&m_browserFuncs, + &m_pluginFuncs, + m_env, + pluginObject) != NPERR_NO_ERROR) { + PLUGIN_LOG("Couldn't initialize plugin\n"); + return false; + } + + // Add the Plugin to the PluginList + jobject pluginListObject = getPluginListObject(); + if(!pluginListObject) { + PLUGIN_LOG("Couldn't get PluginList object\n"); + m_NP_Shutdown(); + return false; + } + if(!addPluginObjectToList(pluginListObject, pluginObject)) { + PLUGIN_LOG("Couldn't add Plugin to PluginList\n"); + m_NP_Shutdown(); + return false; + } + + // Retain the Java Plugin object + m_pluginObject = m_env->NewGlobalRef(pluginObject); + + // Need to call NP_Shutdown at some point in the future. + m_libraryInitialized = true; + + // Don't close the library - loaded OK. + dlCloser.ok(); + // Retain the handle so we can close it in the future. + m_libraryHandle = handle; + + PLUGIN_LOG("Loaded OK\n"); + return true; +} + +void PluginPackageAndroid::unload() +{ + if(!m_libraryHandle) { + PLUGIN_LOG("Plugin \"%s\" already unloaded\n", m_path.utf8().data()); + return; // No library loaded + } + PLUGIN_LOG("Unloading \"%s\"\n", m_path.utf8().data()); + + if(m_libraryInitialized) { + // Shutdown the plug-in + ASSERT(m_NP_Shutdown != NULL); + PLUGIN_LOG("Calling NP_Shutdown\n"); + NPError err = m_NP_Shutdown(); + if(err != NPERR_NO_ERROR) + PLUGIN_LOG("Couldn't shutdown plug-in \"%s\"\n", + m_path.utf8().data()); + m_libraryInitialized = false; + + // Remove the plugin from the PluginList + if(m_pluginObject) { + jobject pluginListObject = getPluginListObject(); + if(pluginListObject) { + removePluginObjectFromList(pluginListObject, m_pluginObject); + } + // Remove a reference to the Plugin object so it can + // garbage collect. + m_env->DeleteGlobalRef(m_pluginObject); + m_pluginObject = 0; + } + } + + PLUGIN_LOG("Closing library\n"); + dlclose(m_libraryHandle); + m_libraryHandle = 0; + memset(&m_browserFuncs, 0, sizeof(m_browserFuncs)); + memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); + m_NP_Initialize = 0; + m_NP_Shutdown = 0; + m_NP_GetMIMEDescription = 0; + m_NP_GetValue = 0; +} + +const NPPluginFuncs* PluginPackageAndroid::pluginFuncs() const +{ + ASSERT(m_libraryHandle && m_libraryInitialized); + return &m_pluginFuncs; +} + +PluginPackageAndroid* PluginPackageAndroid::createPackage(const String& path, + uint32 lastModified) +{ + PluginPackageAndroid* package = new PluginPackageAndroid(path, + lastModified); + + if (!package->load()) { + delete package; + return 0; + } + + return package; +} + +bool PluginPackageAndroid::getEntryPoint(const char *name, void **entry_point) +{ + dlerror(); + *entry_point = dlsym(m_libraryHandle, name); + const char *error = dlerror(); + if(error == NULL && *entry_point != NULL) { + return true; + } else { + PLUGIN_LOG("Couldn't get entry point \"%s\": %s\n", + name, error); + return false; + } +} + +bool PluginPackageAndroid::initializeMIMEEntry(const String& mimeEntry) +{ + // Each part is split into 3 fields separated by colons + // Field 1 is the MIME type (e.g "application/x-shockwave-flash"). + // Field 2 is a comma separated list of file extensions. + // Field 3 is a human readable short description. + Vector<String> fields = mimeEntry.split(':', true); + if(fields.size() != 3) + return false; + + const String& mimeType = fields[0]; + Vector<String> extensions = fields[1].split(',', true); + const String& description = fields[2]; + + PLUGIN_LOG("mime_type: \"%s\"\n", + mimeType.utf8().data()); + PLUGIN_LOG("extensions: \"%s\"\n", + fields[1].utf8().data()); + PLUGIN_LOG("description: \"%s\"\n", + description.utf8().data()); + + // Map the mime type to the vector of extensions and the description + if(!extensions.isEmpty()) + m_mimeToExtensions.set(mimeType, extensions); + if(!description.isEmpty()) + m_mimeToDescriptions.set(mimeType, description); + + return true; +} + +bool PluginPackageAndroid::initializeMIMEDescription( + const String& mimeDescription) +{ + PLUGIN_LOG("MIME description: \"%s\"\n", mimeDescription.utf8().data()); + + // Clear out the current mappings. + m_mimeToDescriptions.clear(); + m_mimeToExtensions.clear(); + + // Split the description into its component entries, separated by + // semicolons. + Vector<String> mimeEntries = mimeDescription.split(';', true); + + // Iterate through the entries, adding them to the MIME mappings. + for(Vector<String>::const_iterator it = mimeEntries.begin(); + it != mimeEntries.end(); ++it) { + if(!initializeMIMEEntry(*it)) { + PLUGIN_LOG("Bad MIME entry: \"%s\"\n", it->utf8().data()); + m_mimeToDescriptions.clear(); + m_mimeToExtensions.clear(); + return false; + } + } + + return true; +} + +PluginPackageAndroid::DynamicLibraryCloser::~DynamicLibraryCloser() +{ + // Close the PluginPackageAndroid's library + if(m_package) + { + if(m_package->m_libraryHandle) + { + dlclose(m_package->m_libraryHandle); + m_package->m_libraryHandle = NULL; + } + m_package = NULL; + } +} + +} // namespace WebCore + +#endif diff --git a/WebCore/plugins/android/PluginPackageAndroid.h b/WebCore/plugins/android/PluginPackageAndroid.h new file mode 100644 index 0000000..d78df1e --- /dev/null +++ b/WebCore/plugins/android/PluginPackageAndroid.h @@ -0,0 +1,152 @@ +#ifdef ANDROID_PLUGINS + +/* + * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#ifndef PluginPackageAndroid_H +#define PluginPackageAndroid_H + +#include "PlatformString.h" +#include "StringHash.h" +#include "Timer.h" +#include "npfunctions.h" +#include <wtf/HashMap.h> +#include "wtf/RefCounted.h" + +namespace WebCore { + typedef HashMap<String, String> MIMEToDescriptionsMap; + typedef HashMap<String, Vector<String> > MIMEToExtensionsMap; + + class PluginPackageAndroid : public RefCounted<PluginPackageAndroid> { + public: + ~PluginPackageAndroid(); + static PluginPackageAndroid* createPackage(const String& path, + uint32 lastModified); + + String path() const { return m_path; } + String name() const { return m_name; } + String fileName() const { return m_fileName; } + String description() const { return m_description; } + uint32 getLastModified() const { return m_lastModified; } + + const MIMEToDescriptionsMap& mimeToDescriptions() const { + return m_mimeToDescriptions; + } + const MIMEToExtensionsMap& mimeToExtensions() const { + return m_mimeToExtensions; + } + + bool load(); + void unload(); + + const NPPluginFuncs* pluginFuncs() const; + + private: + // Simple class which calls dlclose() on a dynamic library when going + // out of scope. Call ok() if the handle should stay open. + class DynamicLibraryCloser + { + public: + DynamicLibraryCloser(PluginPackageAndroid *package) + : m_package(package) { } + ~DynamicLibraryCloser(); + void ok() { m_package = NULL; } + private: + PluginPackageAndroid *m_package; + }; + friend class DynamicLibraryCloser; + + PluginPackageAndroid(const String& path, + uint32 lastModified); + + // Set all the NPN function pointers in m_browserFuncs + void initializeBrowserFuncs(); + + // Call dlsym() and set *entry_point to the return value for + // the symbol 'name'. Return true if the symbol exists. + bool getEntryPoint(const char *name, void **entry_point); + + // Initialize m_mimeToDescriptions and m_mimeToExtensions from + // this individual MIME entry. If badly formatted, returns + // false. + bool initializeMIMEEntry(const String& mime_entry); + + // Splits the MIME description into its entries and passes + // them to initializeMIMEEntry. Returns false if any of the + // description is badly format. + bool initializeMIMEDescription(const String& mime_description); + + // Create a Java Plugin object instance + jobject createPluginObject(const char *name, + const char *path, + const char *fileName, + const char *description); + + // Get hold of the Java PluginList instance. + jobject getPluginListObject(); + + // Add the plugin to the PluginList. + bool addPluginObjectToList(jobject pluginList, + jobject plugin); + + // Remove the plugin from the Pluginlist + void removePluginObjectFromList(jobject pluginList, + jobject plugin); + + String m_path; // Path to open this library + String m_name; // Human readable name e.g "Shockwave Flash" + String m_fileName; // Name of the file e.g "libflashplayer.so" + String m_description; // Verbose string e.g "Shockwave Flash 9.0 r48" + uint32 m_lastModified; // Last modification time, Unix seconds. + + NPNetscapeFuncs m_browserFuncs; + NPPluginFuncs m_pluginFuncs; + MIMEToDescriptionsMap m_mimeToDescriptions; + MIMEToExtensionsMap m_mimeToExtensions; + + // The Java environment. + JNIEnv *m_env; + + // The Java Plugin object. + jobject m_pluginObject; + + // Handle to the dynamic library. Non-NULL if open. + void *m_libraryHandle; + + // True if the library is in the initialized state + // (NP_Initialize called) + bool m_libraryInitialized; + + // Entry points into the library obtained using dlsym() + NP_InitializeFuncPtr m_NP_Initialize; + NP_ShutdownFuncPtr m_NP_Shutdown; + NP_GetMIMEDescriptionFuncPtr m_NP_GetMIMEDescription; + NP_GetValueFuncPtr m_NP_GetValue; + }; +} // namespace WebCore + +#endif + +#endif diff --git a/WebCore/plugins/android/PluginViewAndroid.cpp b/WebCore/plugins/android/PluginViewAndroid.cpp new file mode 100644 index 0000000..87dbe11 --- /dev/null +++ b/WebCore/plugins/android/PluginViewAndroid.cpp @@ -0,0 +1,567 @@ +#ifdef ANDROID_PLUGINS + +/* + * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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 "config.h" +#include "PluginViewAndroid.h" + +#include "Document.h" +#include "Element.h" +#include "FrameLoader.h" +#include "FrameLoadRequest.h" +#include "FrameTree.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLNames.h" +#include "HTMLPlugInElement.h" +#include "Image.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "Page.h" +#include "PlatformGraphicsContext.h" +#include "PluginPackageAndroid.h" +#include "kjs_binding.h" +#include "kjs_proxy.h" +#include "kjs_window.h" +#include "android_graphics.h" +#include "SkCanvas.h" +#include "npruntime_impl.h" +#include "runtime_root.h" +#include "Settings.h" +#include <kjs/JSLock.h> +#include <kjs/value.h> +#include <wtf/ASCIICType.h> +#include "runtime.h" +#include "WebViewCore.h" + +#include "PluginDebug.h" + +using KJS::ExecState; +using KJS::Interpreter; +using KJS::JSLock; +using KJS::JSObject; +using KJS::JSValue; +using KJS::UString; + +using std::min; + +using namespace WTF; + +namespace WebCore { + +using namespace HTMLNames; + +PluginViewAndroid* PluginViewAndroid::s_currentPluginView = 0; + +void PluginViewAndroid::setParent(ScrollView* parent) +{ + if (parent) + init(); +} + +bool PluginViewAndroid::start() +{ + if (m_isStarted) + return false; + + ASSERT(m_plugin); + ASSERT(m_plugin->pluginFuncs()->newp); + + NPError npErr; + PluginViewAndroid::setCurrentPluginView(this); + { + KJS::JSLock::DropAllLocks dropAllLocks; + npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.data(), + m_instance, + m_mode, + m_paramCount, + m_paramNames, + m_paramValues, + NULL); + if(npErr) + PLUGIN_LOG("plugin->newp returned %d\n", static_cast<int>(npErr)); + } + PluginViewAndroid::setCurrentPluginView(0); + + if (npErr != NPERR_NO_ERROR) + return false; + + m_isStarted = true; + + return true; +} + +void PluginViewAndroid::stop() +{ + if (!m_isStarted) + return; + + m_isStarted = false; + + KJS::JSLock::DropAllLocks dropAllLocks; + + // Destroy the plugin + NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, 0); + if(npErr) + PLUGIN_LOG("Plugin destroy returned %d\n", static_cast<int>(npErr)); + + m_instance->pdata = 0; +} + +void PluginViewAndroid::setCurrentPluginView(PluginViewAndroid* pluginView) +{ + s_currentPluginView = pluginView; +} + +PluginViewAndroid* PluginViewAndroid::currentPluginView() +{ + return s_currentPluginView; +} + +static char* createUTF8String(const String& str) +{ + CString cstr = str.utf8(); + char* result = reinterpret_cast<char*>(fastMalloc(cstr.length() + 1)); + + strncpy(result, cstr.data(), cstr.length() + 1); + + return result; +} + +static void freeStringArray(char** stringArray, int length) +{ + if (!stringArray) + return; + + for (int i = 0; i < length; i++) + fastFree(stringArray[i]); + + fastFree(stringArray); +} + +NPError PluginViewAndroid::getURLNotify(const char* url, + const char* target, + void* notifyData) +{ + notImplemented(); + return NPERR_GENERIC_ERROR; +} + +NPError PluginViewAndroid::getURL(const char* url, const char* target) +{ + notImplemented(); + return NPERR_GENERIC_ERROR; +} + +NPError PluginViewAndroid::postURLNotify(const char* url, + const char* target, + uint32 len, + const char* buf, + NPBool file, + void* notifyData) +{ + notImplemented(); + return NPERR_GENERIC_ERROR; +} + +NPError PluginViewAndroid::postURL(const char* url, + const char* target, + uint32 len, + const char* buf, + NPBool file) +{ + notImplemented(); + return NPERR_GENERIC_ERROR; +} + +NPError PluginViewAndroid::newStream(NPMIMEType type, + const char* target, + NPStream** stream) +{ + notImplemented(); + return NPERR_GENERIC_ERROR; +} + +int32 PluginViewAndroid::write(NPStream* stream, + int32 len, + void* buffer) +{ + notImplemented(); + return -1; +} + +NPError PluginViewAndroid::destroyStream(NPStream* stream, NPReason reason) +{ + notImplemented(); + return NPERR_GENERIC_ERROR; +} + +const char* PluginViewAndroid::userAgent() +{ + if (m_userAgent.isNull()) + m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8(); + return m_userAgent.data(); +} + +void PluginViewAndroid::status(const char* message) +{ + String s = DeprecatedString::fromLatin1(message); + + if (Page* page = m_parentFrame->page()) + page->chrome()->setStatusbarText(m_parentFrame, s); +} + +NPError PluginViewAndroid::getValue(NPNVariable variable, void* value) +{ + switch (variable) { + case NPNVWindowNPObject: { + NPObject* windowScriptObject = + m_parentFrame->windowScriptNPObject(); + + // Return value is expected to be retained, as described + // here: + // <http://www.mozilla.org/projects/plugin/npruntime.html> + if (windowScriptObject) + _NPN_RetainObject(windowScriptObject); + + void** v = (void**)value; + *v = windowScriptObject; + + return NPERR_NO_ERROR; + } + + case NPNVPluginElementNPObject: { + NPObject* pluginScriptObject = 0; + + if (m_element->hasTagName(appletTag) || + m_element->hasTagName(embedTag) || + m_element->hasTagName(objectTag)) { + HTMLPlugInElement* pluginElement = + static_cast<HTMLPlugInElement*>(m_element); + pluginScriptObject = pluginElement->getNPObject(); + } + + // Return value is expected to be retained, as described + // here: + // <http://www.mozilla.org/projects/plugin/npruntime.html> + if (pluginScriptObject) + _NPN_RetainObject(pluginScriptObject); + + void** v = (void**)value; + *v = pluginScriptObject; + + return NPERR_NO_ERROR; + } + + case NPNVnetscapeWindow: { + // Return the top level WebView Java object associated + // with this instance. + jobject *retObject = static_cast<jobject*>(value); + // Dig down through to the parent frame's WebCoreViewBridge + FrameView* frameView = m_parentFrame->view(); + WebCoreViewBridge* bridge = frameView->getWebCoreViewBridge(); + // Go up parents until we reach the top level. + while (bridge->getParent() != NULL) + bridge = bridge->getParent(); + // This is actually an instance of WebCoreView. + android::WebViewCore* webViewCore = + static_cast<android::WebViewCore*>(bridge); + // Finally, get hold of the Java WebView instance. + *retObject = webViewCore->getWebViewJavaObject(); + return NPERR_NO_ERROR; + } + default: + return NPERR_GENERIC_ERROR; + } +} + +NPError PluginViewAndroid::setValue(NPPVariable variable, void* value) +{ + switch (variable) { + case NPPVpluginWindowBool: + m_isWindowed = value; + return NPERR_NO_ERROR; + case NPPVpluginTransparentBool: + m_isTransparent = value; + return NPERR_NO_ERROR; + default: + notImplemented(); + return NPERR_GENERIC_ERROR; + } +} + +void PluginViewAndroid::invalidateRect(NPRect* rect) +{ + notImplemented(); +} + +void PluginViewAndroid::invalidateRegion(NPRegion region) +{ + notImplemented(); +} + +void PluginViewAndroid::forceRedraw() +{ + notImplemented(); +} + +KJS::Bindings::Instance* PluginViewAndroid::bindingInstance() +{ + NPObject* object = 0; + + if (!m_plugin || !m_plugin->pluginFuncs()->getvalue) + return 0; + + NPError npErr; + { + KJS::JSLock::DropAllLocks dropAllLocks; + npErr = m_plugin->pluginFuncs()->getvalue(m_instance, + NPPVpluginScriptableNPObject, + &object); + } + + if (npErr != NPERR_NO_ERROR || !object) + return 0; + + RefPtr<KJS::Bindings::RootObject> root = m_parentFrame->createRootObject( + this, + m_parentFrame->scriptProxy()->globalObject()); + KJS::Bindings::Instance *instance = + KJS::Bindings::Instance::createBindingForLanguageInstance( + KJS::Bindings::Instance::CLanguage, + object, + root.release()); + + _NPN_ReleaseObject(object); + + return instance; +} + +PluginViewAndroid::~PluginViewAndroid() +{ + stop(); + + freeStringArray(m_paramNames, m_paramCount); + freeStringArray(m_paramValues, m_paramCount); + + m_parentFrame->cleanupScriptObjectsForPlugin(this); + + // Don't unload the plugin - let the reference count clean it up. + + // Can't use RefPtr<> because it's name clashing with SkRefCnt<> + m_viewBridge->unref(); +} + +void PluginViewAndroid::setParameters(const Vector<String>& paramNames, + const Vector<String>& paramValues) +{ + ASSERT(paramNames.size() == paramValues.size()); + + // Also pass an extra parameter + unsigned size = paramNames.size() + 1; + unsigned paramCount = 0; + + m_paramNames = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size)); + m_paramValues = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size)); + + for (unsigned i = 0; i < paramNames.size(); i++) { + if (equalIgnoringCase(paramNames[i], "windowlessvideo")) + continue; + // Don't let the HTML element specify this value! + if (equalIgnoringCase(paramNames[i], "android_plugins_dir")) + continue; + + m_paramNames[paramCount] = createUTF8String(paramNames[i]); + m_paramValues[paramCount] = createUTF8String(paramValues[i]); + + paramCount++; + } + + // Pass the location of the plug-ins directory so the plug-in + // knows where it can store any data it needs. + WebCore::String path = m_parentFrame->settings()->pluginsPath(); + m_paramNames[paramCount] = createUTF8String("android_plugins_dir"); + m_paramValues[paramCount] = createUTF8String(path.utf8().data()); + paramCount++; + + m_paramCount = paramCount; +} + +PluginViewAndroid::PluginViewAndroid(Frame* parentFrame, + const IntSize& size, + PluginPackageAndroid* plugin, + Element* element, + const KURL& url, + const Vector<String>& paramNames, + const Vector<String>& paramValues, + const String& mimeType, + bool loadManually) + : m_plugin(plugin) + , m_element(element) + , m_parentFrame(parentFrame) + , m_userAgent() + , m_isStarted(false) + , m_url(url) + , m_status(PluginStatusLoadedSuccessfully) + , m_mode(0) + , m_paramCount(0) + , m_paramNames(0) + , m_paramValues(0) + , m_mimeType() + , m_instance() + , m_instanceStruct() + , m_isWindowed(true) + , m_isTransparent(false) + , m_haveInitialized(false) + , m_lastMessage(0) + , m_loadManually(loadManually) + , m_viewBridge(new PluginViewBridgeAndroid()) +{ + setWebCoreViewBridge(m_viewBridge); + + if (!m_plugin) { + m_status = PluginStatusCanNotFindPlugin; + return; + } + + m_instance = &m_instanceStruct; + m_instance->ndata = this; + + m_mimeType = mimeType.utf8(); + + setParameters(paramNames, paramValues); + + m_mode = m_loadManually ? NP_FULL : NP_EMBED; + + resize(size); + + // Early initialisation until we can properly parent this + init(); +} + +void PluginViewAndroid::init() +{ + if (m_haveInitialized) + return; + m_haveInitialized = true; + + if (!m_plugin) { + ASSERT(m_status == PluginStatusCanNotFindPlugin); + return; + } + + if (!m_plugin->load()) { + m_plugin = 0; + m_status = PluginStatusCanNotLoadPlugin; + return; + } + + if (!start()) { + m_status = PluginStatusCanNotLoadPlugin; + return; + } + + m_status = PluginStatusLoadedSuccessfully; +} + +PluginViewBridgeAndroid::PluginViewBridgeAndroid() +{ + m_image = Image::loadPlatformResource("nullplugin"); + if(m_image) + setSize(m_image->width(), m_image->height()); + else + PLUGIN_LOG("Couldn't get nullplugin image\n"); +} + +PluginViewBridgeAndroid::~PluginViewBridgeAndroid() +{ + delete m_image; +} + +void PluginViewBridgeAndroid::draw(GraphicsContext* gc, + const IntRect& rect, + bool) +{ + if (gc->paintingDisabled() || !m_image) + return; + + // Clip the drawing rectangle to our bounds in case it is larger. + IntRect transRect(rect); + IntRect bounds = this->getBounds(); + transRect.intersect(bounds); + + // Move the drawing rectangle into our coordinate space. + transRect.move(-bounds.x(), -bounds.y()); + + // Translate the canvas by the view's location so that things will draw + // in the right place. Clip the canvas to the drawing rectangle. + SkRect r; + android_setrect(&r, transRect); + if (r.isEmpty()) + return; + SkCanvas* canvas = gc->platformContext()->mCanvas; + canvas->save(); + canvas->translate(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y())); + canvas->clipRect(r); + + // Calculate where to place the image so it appears in the center of the + // view. + int imageWidth = m_image->width(); + int imageHeight = m_image->height(); + IntRect centerRect(0, 0, imageWidth, imageHeight); + IntSize c1(bounds.width()/2, bounds.height()/2); + IntSize c2(centerRect.width()/2, centerRect.height()/2); + IntSize diff = c1 - c2; + centerRect.move(diff); + + // Now move the top-left corner of the image to the top-left corner of + // the view so that the tiling will hit the center image. + while (diff.width() > 0) + diff.setWidth(diff.width() - imageWidth); + while (diff.height() > 0) + diff.setHeight(diff.height() - imageHeight); + + // Draw the tiled transparent image adding one extra image width and + // height so that we get a complete fill. + gc->beginTransparencyLayer(0.1); + gc->drawTiledImage(m_image, + IntRect(diff.width(), diff.height(), + bounds.width() + imageWidth, + bounds.height() + imageHeight), + IntPoint(0, 0), IntSize(imageWidth, imageHeight)); + gc->endTransparencyLayer(); + + // Draw the image in the center. + gc->drawImage(m_image, centerRect); + + // Restore our canvas + canvas->restore(); +} + +} // namespace WebCore + +#endif // defined(ANDROID_PLUGINS) diff --git a/WebCore/plugins/android/PluginViewAndroid.h b/WebCore/plugins/android/PluginViewAndroid.h new file mode 100644 index 0000000..d4e55b8 --- /dev/null +++ b/WebCore/plugins/android/PluginViewAndroid.h @@ -0,0 +1,176 @@ +#ifdef ANDROID_PLUGINS + +/* + * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#ifndef PluginViewAndroid_H +#define PluginViewAndroid_H + +#include "CString.h" +#include "IntRect.h" +#include "KURL.h" +#include "PlatformString.h" +#include "ResourceRequest.h" +#include "Widget.h" +#include "npapi.h" +#include "WebCoreViewBridge.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace KJS { + namespace Bindings { + class Instance; + } +} + +namespace WebCore { + class Element; + class Frame; + class Image; + class KURL; + class PluginPackageAndroid; + + enum PluginStatus { + PluginStatusCanNotFindPlugin, + PluginStatusCanNotLoadPlugin, + PluginStatusLoadedSuccessfully + }; + + class PluginViewBridgeAndroid : public WebCoreViewBridge { + public: + PluginViewBridgeAndroid(); + ~PluginViewBridgeAndroid(); + virtual void draw(GraphicsContext* gc, const IntRect& rect, bool); + private: + Image* m_image; + }; + + class PluginViewAndroid : public Widget { + public: + PluginViewAndroid(Frame* parentFrame, + const IntSize&, + PluginPackageAndroid* plugin, + Element*, + const KURL&, + const Vector<String>& paramNames, + const Vector<String>& paramValues, + const String& mimeType, + bool loadManually); + virtual ~PluginViewAndroid(); + + PluginPackageAndroid* plugin() const { return m_plugin.get(); } + NPP instance() const { return m_instance; } + + static PluginViewAndroid* currentPluginView(); + + KJS::Bindings::Instance* bindingInstance(); + + PluginStatus status() const { return m_status; } + + // NPN stream functions + NPError getURLNotify(const char* url, + const char* target, + void* notifyData); + NPError getURL(const char* url, + const char* target); + NPError postURLNotify(const char* url, + const char* target, + uint32 len, + const char* but, + NPBool file, + void* notifyData); + NPError postURL(const char* url, + const char* target, + uint32 len, + const char* but, + NPBool file); + NPError newStream(NPMIMEType type, + const char* target, + NPStream** stream); + int32 write(NPStream* stream, int32 len, void* buffer); + NPError destroyStream(NPStream* stream, NPReason reason); + + // NPN misc functions + const char* userAgent(); + void status(const char* message); + NPError getValue(NPNVariable variable, void* value); + NPError setValue(NPPVariable variable, void* value); + + // NPN UI functions + void invalidateRect(NPRect*); + void invalidateRegion(NPRegion); + void forceRedraw(); + + // Widget functions + virtual void setParent(ScrollView*); + + private: + void setParameters(const Vector<String>& paramNames, + const Vector<String>& paramValues); + void init(); + bool start(); + void stop(); + static void setCurrentPluginView(PluginViewAndroid*); + + // Maintain a refcount on the plugin. It should be deleted + // once all views no longer reference it. + RefPtr<PluginPackageAndroid> m_plugin; + Element* m_element; + Frame* m_parentFrame; + CString m_userAgent; + bool m_isStarted; + KURL m_url; + PluginStatus m_status; + + int m_mode; + int m_paramCount; + char** m_paramNames; + char** m_paramValues; + + CString m_mimeType; + NPP m_instance; + NPP_t m_instanceStruct; + + bool m_isWindowed; + bool m_isTransparent; + bool m_haveInitialized; + + unsigned m_lastMessage; + + bool m_loadManually; + + // Sorry, can't use RefPtr<> due to name collision with SkRefCnt. + PluginViewBridgeAndroid *m_viewBridge; + + static PluginViewAndroid* s_currentPluginView; + }; + +} // namespace WebCore + +#endif + +#endif // defined(ANDROID_PLUGINS) diff --git a/WebCore/plugins/android/npapi.cpp b/WebCore/plugins/android/npapi.cpp new file mode 100644 index 0000000..23007eb --- /dev/null +++ b/WebCore/plugins/android/npapi.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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 "config.h" + +#ifdef ANDROID_PLUGINS +// Needed for NPN_PluginThreadAsyncCall, which calls +// JavaSharedClient::EnqueueFunctionPtr(). +#include "JavaSharedClient.h" +#endif +#include "WebCoreJni.h" +#include "PluginInfoStore.h" +#include "PluginViewAndroid.h" +#include "jni.h" +#include "npapi.h" + +#include "PluginDebug.h" + +using namespace WebCore; + +// The plugin view is always the ndata of the instance,. Sometimes, plug-ins will call an instance-specific function +// with a NULL instance. To workaround this, call the last plug-in view that made a call to a plug-in. +// Currently, the current plug-in view is only set before NPP_New in PluginViewAndroid::start. +// This specifically works around Flash and Shockwave. When we call NPP_New, they call NPN_Useragent with a NULL instance. +static PluginViewAndroid* pluginViewForInstance(NPP instance) +{ + if (instance && instance->ndata) + return static_cast<PluginViewAndroid*>(instance->ndata); + return PluginViewAndroid::currentPluginView(); +} + +void* NPN_MemAlloc(uint32 size) +{ + return malloc(size); +} + +void NPN_MemFree(void* ptr) +{ + free(ptr); +} + +uint32 NPN_MemFlush(uint32 size) +{ + // Do nothing + return 0; +} + +void NPN_ReloadPlugins(NPBool reloadPages) +{ + refreshPlugins(reloadPages); +} + +NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList) +{ + return NPERR_STREAM_NOT_SEEKABLE; +} + +NPError NPN_GetURLNotify(NPP instance, const char* url, const char* target, void* notifyData) +{ + return pluginViewForInstance(instance)->getURLNotify(url, target, notifyData); +} + +NPError NPN_GetURL(NPP instance, const char* url, const char* target) +{ + return pluginViewForInstance(instance)->getURL(url, target); +} + +NPError NPN_PostURLNotify(NPP instance, const char* url, const char* target, uint32 len, const char* buf, NPBool file, void* notifyData) +{ + return pluginViewForInstance(instance)->postURLNotify(url, target, len, buf, file, notifyData); +} + +NPError NPN_PostURL(NPP instance, const char* url, const char* target, uint32 len, const char* buf, NPBool file) +{ + return pluginViewForInstance(instance)->postURL(url, target, len, buf, file); +} + +NPError NPN_NewStream(NPP instance, NPMIMEType type, const char* target, NPStream** stream) +{ + return pluginViewForInstance(instance)->newStream(type, target, stream); +} + +int32 NPN_Write(NPP instance, NPStream* stream, int32 len, void* buffer) +{ + return pluginViewForInstance(instance)->write(stream, len, buffer); +} + +NPError NPN_DestroyStream(NPP instance, NPStream* stream, NPReason reason) +{ + return pluginViewForInstance(instance)->destroyStream(stream, reason); +} + +const char* NPN_UserAgent(NPP instance) +{ + PluginViewAndroid* view = pluginViewForInstance(instance); + + // FIXME: Some plug-ins call NPN_UserAgent with a null instance in their NP_initialize function! + // We'd need a way to get a user agent without having a frame around. + if (!view) + return 0; + + return view->userAgent(); +} + +void NPN_Status(NPP instance, const char* message) +{ + pluginViewForInstance(instance)->status(message); +} + +void NPN_InvalidateRect(NPP instance, NPRect* invalidRect) +{ + pluginViewForInstance(instance)->invalidateRect(invalidRect); +} + +void NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion) +{ + pluginViewForInstance(instance)->invalidateRegion(invalidRegion); +} + +void NPN_ForceRedraw(NPP instance) +{ + pluginViewForInstance(instance)->forceRedraw(); +} + +NPError NPN_GetValue(NPP instance, NPNVariable variable, void* value) +{ + return pluginViewForInstance(instance)->getValue(variable, value); +} + +NPError NPN_SetValue(NPP instance, NPPVariable variable, void* value) +{ + return pluginViewForInstance(instance)->setValue(variable, value); +} + +void* NPN_GetJavaEnv() +{ + // This is supposed to return the JRIEnv, but nobody's been using + // that interface for years. Far more useful to return the JNIEnv, + // so we'll do that... + JNIEnv* env = NULL; + if (android::WebCoreJni::getJavaVM()->GetEnv((void**) &env, + JNI_VERSION_1_4) != JNI_OK) { + PLUGIN_LOG("GetEnv failed!"); + } + return env; +} + +void* NPN_GetJavaPeer(NPP instance) +{ + // Unsupported + return 0; +} + +void +NPN_PushPopupsEnabledState(NPP instance, NPBool enabled) +{ +} + +void +NPN_PopPopupsEnabledState(NPP instance) +{ +} + +#ifdef ANDROID_PLUGINS +// Added in version 19 NPAPI. Sandbox WebKit has this same function in +// plugins/npapi.cpp rather than plugins/android/npapi.cpp. This file +// goes away after merge. +void NPN_PluginThreadAsyncCall(NPP instance, + void (*func)(void *), + void *userData) +{ + // This is used to marshal a function call onto the main thread, + // so plugins can get around not "owning" the message loop. Note + // that the plugin is responsible for taking care of the potential + // race between the order of NPP_Destroy and callbacks. + JavaSharedClient::EnqueueFunctionPtr(func, userData); +} +#endif diff --git a/WebCore/plugins/android/npfunctions.h b/WebCore/plugins/android/npfunctions.h new file mode 100644 index 0000000..f9a5612 --- /dev/null +++ b/WebCore/plugins/android/npfunctions.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2007 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 COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#ifndef _NPFUNCTIONS_H_ +#define _NPFUNCTIONS_H_ + +#include <jni.h> +#include "npruntime.h" +#include "npapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(XP_WIN) +#define EXPORTED_CALLBACK(_type, _name) _type (__stdcall * _name) +#else +#define EXPORTED_CALLBACK(_type, _name) _type (* _name) +#endif + +typedef NPError (*NPN_GetURLNotifyProcPtr)(NPP instance, const char* URL, const char* window, void* notifyData); +typedef NPError (*NPN_PostURLNotifyProcPtr)(NPP instance, const char* URL, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData); +typedef NPError (*NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList); +typedef NPError (*NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** stream); +typedef int32 (*NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32 len, void* buffer); +typedef NPError (*NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); +typedef void (*NPN_StatusProcPtr)(NPP instance, const char* message); +typedef const char*(*NPN_UserAgentProcPtr)(NPP instance); +typedef void* (*NPN_MemAllocProcPtr)(uint32 size); +typedef void (*NPN_MemFreeProcPtr)(void* ptr); +typedef uint32 (*NPN_MemFlushProcPtr)(uint32 size); +typedef void (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages); +typedef NPError (*NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value); +typedef NPError (*NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value); +typedef void (*NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect); +typedef void (*NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region); +typedef void (*NPN_ForceRedrawProcPtr)(NPP instance); +typedef NPError (*NPN_GetURLProcPtr)(NPP instance, const char* URL, const char* window); +typedef NPError (*NPN_PostURLProcPtr)(NPP instance, const char* URL, const char* window, uint32 len, const char* buf, NPBool file); +typedef void* (*NPN_GetJavaEnvProcPtr)(void); +typedef void* (*NPN_GetJavaPeerProcPtr)(NPP instance); +typedef void (*NPN_PushPopupsEnabledStateProcPtr)(NPP instance, NPBool enabled); +typedef void (*NPN_PopPopupsEnabledStateProcPtr)(NPP instance); + +typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant); + +typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr) (const NPUTF8 *name); +typedef void (*NPN_GetStringIdentifiersProcPtr) (const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers); +typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr) (int32_t intid); +typedef int32_t (*NPN_IntFromIdentifierProcPtr) (NPIdentifier identifier); +typedef bool (*NPN_IdentifierIsStringProcPtr) (NPIdentifier identifier); +typedef NPUTF8 *(*NPN_UTF8FromIdentifierProcPtr) (NPIdentifier identifier); + +typedef NPObject* (*NPN_CreateObjectProcPtr) (NPP, NPClass *aClass); +typedef NPObject* (*NPN_RetainObjectProcPtr) (NPObject *obj); +typedef void (*NPN_ReleaseObjectProcPtr) (NPObject *obj); +typedef bool (*NPN_InvokeProcPtr) (NPP npp, NPObject *obj, NPIdentifier methodName, const NPVariant *args, unsigned argCount, NPVariant *result); +typedef bool (*NPN_InvokeDefaultProcPtr) (NPP npp, NPObject *obj, const NPVariant *args, unsigned argCount, NPVariant *result); +typedef bool (*NPN_EvaluateProcPtr) (NPP npp, NPObject *obj, NPString *script, NPVariant *result); +typedef bool (*NPN_GetPropertyProcPtr) (NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); +typedef bool (*NPN_SetPropertyProcPtr) (NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); +typedef bool (*NPN_HasPropertyProcPtr) (NPP, NPObject *npobj, NPIdentifier propertyName); +typedef bool (*NPN_HasMethodProcPtr) (NPP npp, NPObject *npobj, NPIdentifier methodName); +typedef bool (*NPN_RemovePropertyProcPtr) (NPP npp, NPObject *obj, NPIdentifier propertyName); +typedef void (*NPN_SetExceptionProcPtr) (NPObject *obj, const NPUTF8 *message); +typedef bool (*NPN_EnumerateProcPtr) (NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count); +#ifdef ANDROID_PLUGINS +// Added in version 19 NPAPI. Sandbox WebKit is version 20 and already +// implements this change. +typedef void (*NPN_PluginThreadAsyncCallPtr) (NPP npp, void (*func)(void *), void *userData); +#endif + +typedef NPError (*NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved); +typedef NPError (*NPP_DestroyProcPtr)(NPP instance, NPSavedData** save); +typedef NPError (*NPP_SetWindowProcPtr)(NPP instance, NPWindow* window); +typedef NPError (*NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype); +typedef NPError (*NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); +typedef void (*NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname); +typedef int32 (*NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream); +typedef int32 (*NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer); +typedef void (*NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint); +typedef int16 (*NPP_HandleEventProcPtr)(NPP instance, void* event); +typedef void (*NPP_URLNotifyProcPtr)(NPP instance, const char* URL, NPReason reason, void* notifyData); +typedef NPError (*NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value); +typedef NPError (*NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value); +typedef EXPORTED_CALLBACK(void, NPP_ShutdownProcPtr)(void); + +typedef void *(*NPP_GetJavaClassProcPtr)(void); +typedef void* JRIGlobalRef; //not using this right now + +typedef struct _NPNetscapeFuncs { + uint16 size; + uint16 version; + + NPN_GetURLProcPtr geturl; + NPN_PostURLProcPtr posturl; + NPN_RequestReadProcPtr requestread; + NPN_NewStreamProcPtr newstream; + NPN_WriteProcPtr write; + NPN_DestroyStreamProcPtr destroystream; + NPN_StatusProcPtr status; + NPN_UserAgentProcPtr uagent; + NPN_MemAllocProcPtr memalloc; + NPN_MemFreeProcPtr memfree; + NPN_MemFlushProcPtr memflush; + NPN_ReloadPluginsProcPtr reloadplugins; + NPN_GetJavaEnvProcPtr getJavaEnv; + NPN_GetJavaPeerProcPtr getJavaPeer; + NPN_GetURLNotifyProcPtr geturlnotify; + NPN_PostURLNotifyProcPtr posturlnotify; + NPN_GetValueProcPtr getvalue; + NPN_SetValueProcPtr setvalue; + NPN_InvalidateRectProcPtr invalidaterect; + NPN_InvalidateRegionProcPtr invalidateregion; + NPN_ForceRedrawProcPtr forceredraw; + + NPN_GetStringIdentifierProcPtr getstringidentifier; + NPN_GetStringIdentifiersProcPtr getstringidentifiers; + NPN_GetIntIdentifierProcPtr getintidentifier; + NPN_IdentifierIsStringProcPtr identifierisstring; + NPN_UTF8FromIdentifierProcPtr utf8fromidentifier; + NPN_IntFromIdentifierProcPtr intfromidentifier; + NPN_CreateObjectProcPtr createobject; + NPN_RetainObjectProcPtr retainobject; + NPN_ReleaseObjectProcPtr releaseobject; + NPN_InvokeProcPtr invoke; + NPN_InvokeDefaultProcPtr invokeDefault; + NPN_EvaluateProcPtr evaluate; + NPN_GetPropertyProcPtr getproperty; + NPN_SetPropertyProcPtr setproperty; + NPN_RemovePropertyProcPtr removeproperty; + NPN_HasPropertyProcPtr hasproperty; + NPN_HasMethodProcPtr hasmethod; + NPN_ReleaseVariantValueProcPtr releasevariantvalue; + NPN_SetExceptionProcPtr setexception; + NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate; + NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate; + NPN_EnumerateProcPtr enumerate; +#ifdef ANDROID_PLUGINS + // Added in version 19 NPAPI. Sandbox WebKit is version 20 and + // already implements this change. + NPN_PluginThreadAsyncCallPtr pluginthreadasynccall; +#endif +} NPNetscapeFuncs; + +typedef struct _NPPluginFuncs { + uint16 size; + uint16 version; + NPP_NewProcPtr newp; + NPP_DestroyProcPtr destroy; + NPP_SetWindowProcPtr setwindow; + NPP_NewStreamProcPtr newstream; + NPP_DestroyStreamProcPtr destroystream; + NPP_StreamAsFileProcPtr asfile; + NPP_WriteReadyProcPtr writeready; + NPP_WriteProcPtr write; + NPP_PrintProcPtr print; + NPP_HandleEventProcPtr event; + NPP_URLNotifyProcPtr urlnotify; + JRIGlobalRef javaClass; + NPP_GetValueProcPtr getvalue; + NPP_SetValueProcPtr setvalue; +} NPPluginFuncs; + +typedef NPError (*NP_InitializeFuncPtr)(NPNetscapeFuncs *netscape_funcs, + NPPluginFuncs *plugin_funcs, + JNIEnv *java_environment, + jobject application_context); +typedef NPError (*NP_ShutdownFuncPtr)(); +typedef char* (*NP_GetMIMEDescriptionFuncPtr)(); +typedef NPError (*NP_GetValueFuncPtr)(void *instance, + NPPVariable var, + void *value); + +#ifdef __cplusplus +} +#endif + +#endif |