diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 9364f22aed35e1a1e9d07c121510f80be3ab0502 (patch) | |
tree | d49911209b132da58d838efa852daf28d516df21 /WebCore/plugins | |
parent | 87eb0cb35bad8784770ebc807e6c982432e47107 (diff) | |
download | external_webkit-9364f22aed35e1a1e9d07c121510f80be3ab0502.zip external_webkit-9364f22aed35e1a1e9d07c121510f80be3ab0502.tar.gz external_webkit-9364f22aed35e1a1e9d07c121510f80be3ab0502.tar.bz2 |
Initial Contribution
Diffstat (limited to 'WebCore/plugins')
21 files changed, 2885 insertions, 580 deletions
diff --git a/WebCore/plugins/PluginDatabase.cpp b/WebCore/plugins/PluginDatabase.cpp deleted file mode 100644 index dba5ef9..0000000 --- a/WebCore/plugins/PluginDatabase.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. 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 "PluginDatabase.h" - -#include "Frame.h" -#include "KURL.h" -#include "PluginPackage.h" -#include <stdlib.h> - -namespace WebCore { - -PluginDatabase* PluginDatabase::installedPlugins() -{ - static PluginDatabase* plugins = 0; - - if (!plugins) { - plugins = new PluginDatabase; - plugins->setPluginPaths(PluginDatabase::defaultPluginPaths()); - plugins->refresh(); - } - - return plugins; -} - -bool PluginDatabase::isMIMETypeRegistered(const String& mimeType) -{ - if (mimeType.isNull()) - return false; - if (m_registeredMIMETypes.contains(mimeType)) - return true; - // No plugin was found, try refreshing the database and searching again - return (refresh() && m_registeredMIMETypes.contains(mimeType)); -} - -void PluginDatabase::addExtraPluginPath(const String& path) -{ - m_pluginPaths.append(path); - refresh(); -} - -bool PluginDatabase::refresh() -{ - PluginSet newPlugins; - - bool pluginSetChanged = false; - - // Create a new set of plugins - newPlugins = getPluginsInPaths(); - - if (!m_plugins.isEmpty()) { - m_registeredMIMETypes.clear(); - - PluginSet pluginsToUnload = m_plugins; - - PluginSet::const_iterator end = newPlugins.end(); - for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it) - pluginsToUnload.remove(*it); - - end = m_plugins.end(); - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) - newPlugins.remove(*it); - - // Unload plugins - end = pluginsToUnload.end(); - for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it) - m_plugins.remove(*it); - - // Add new plugins - end = newPlugins.end(); - for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it) - m_plugins.add(*it); - - pluginSetChanged = !pluginsToUnload.isEmpty() || !newPlugins.isEmpty(); - } else { - m_plugins = newPlugins; - PluginSet::const_iterator end = newPlugins.end(); - for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it) - m_plugins.add(*it); - - pluginSetChanged = !newPlugins.isEmpty(); - } - - // Register plug-in MIME types - PluginSet::const_iterator end = m_plugins.end(); - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { - // Get MIME types - MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end(); - for (MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin(); map_it != map_end; ++map_it) { - m_registeredMIMETypes.add(map_it->first); - } - } - - return pluginSetChanged; -} - -Vector<PluginPackage*> PluginDatabase::plugins() const -{ - Vector<PluginPackage*> result; - - PluginSet::const_iterator end = m_plugins.end(); - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) - result.append((*it).get()); - - return result; -} - -int PluginDatabase::preferredPluginCompare(const void* a, const void* b) -{ - PluginPackage* pluginA = *static_cast<PluginPackage* const*>(a); - PluginPackage* pluginB = *static_cast<PluginPackage* const*>(b); - - return pluginA->compare(*pluginB); -} - -PluginPackage* PluginDatabase::pluginForMIMEType(const String& mimeType) -{ - if (mimeType.isEmpty()) - return 0; - - String key = mimeType.lower(); - PluginSet::const_iterator end = m_plugins.end(); - - Vector<PluginPackage*, 2> pluginChoices; - - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { - if ((*it)->mimeToDescriptions().contains(key)) - pluginChoices.append((*it).get()); - } - - if (pluginChoices.isEmpty()) - return 0; - - qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare); - - return pluginChoices[0]; -} - -String PluginDatabase::MIMETypeForExtension(const String& extension) const -{ - if (extension.isEmpty()) - return String(); - - PluginSet::const_iterator end = m_plugins.end(); - String mimeType; - Vector<PluginPackage*, 2> pluginChoices; - HashMap<PluginPackage*, String> mimeTypeForPlugin; - - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { - MIMEToExtensionsMap::const_iterator mime_end = (*it)->mimeToExtensions().end(); - - for (MIMEToExtensionsMap::const_iterator mime_it = (*it)->mimeToExtensions().begin(); mime_it != mime_end; ++mime_it) { - const Vector<String>& extensions = mime_it->second; - bool foundMapping = false; - for (unsigned i = 0; i < extensions.size(); i++) { - if (equalIgnoringCase(extensions[i], extension)) { - PluginPackage* plugin = (*it).get(); - pluginChoices.append(plugin); - mimeTypeForPlugin.add(plugin, mime_it->first); - foundMapping = true; - break; - } - } - if (foundMapping) - break; - } - } - - if (pluginChoices.isEmpty()) - return String(); - - qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare); - - return mimeTypeForPlugin.get(pluginChoices[0]); -} - -PluginPackage* PluginDatabase::findPlugin(const KURL& url, String& mimeType) -{ - PluginPackage* 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); - plugin = pluginForMIMEType(mimeType); - } - } - } - - // FIXME: if no plugin could be found, query Windows for the mime type - // corresponding to the extension. - - return plugin; -} - -} diff --git a/WebCore/plugins/PluginDatabase.h b/WebCore/plugins/PluginDatabase.h index f79b881..71181b0 100644 --- a/WebCore/plugins/PluginDatabase.h +++ b/WebCore/plugins/PluginDatabase.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,40 +26,47 @@ #ifndef PluginDatabase_H #define PluginDatabase_H -#include "PlatformString.h" -#include "PluginPackage.h" -#include "StringHash.h" +#ifdef ANDROID_PLUGINS + +#include "PluginDatabaseAndroid.h" + +namespace WebCore { + typedef PluginDatabaseAndroid PluginDatabase; +} + +#else // !defined(ANDROID_PLUGINS) #include <wtf/Vector.h> #include <wtf/HashSet.h> +#include "PlatformString.h" +#include "PluginPackage.h" +#include "StringHash.h" + namespace WebCore { class Element; class Frame; class IntSize; class KURL; class PluginPackage; + class PluginView; typedef HashSet<RefPtr<PluginPackage>, PluginPackageHash> PluginSet; class PluginDatabase { public: static PluginDatabase* installedPlugins(); + PluginView* 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<PluginPackage*> plugins() const; bool isMIMETypeRegistered(const String& mimeType); void addExtraPluginPath(const String&); - - static bool isPreferredPluginPath(const String& path); - static int preferredPluginCompare(const void*, const void*); - - PluginPackage* findPlugin(const KURL&, String& mimeType); - private: void setPluginPaths(const Vector<String>& paths) { m_pluginPaths = paths; } PluginSet getPluginsInPaths() const; + PluginPackage* findPlugin(const KURL& url, String& mimeType); PluginPackage* pluginForMIMEType(const String& mimeType); String MIMETypeForExtension(const String& extension) const; @@ -73,4 +79,6 @@ namespace WebCore { } // namespace WebCore +#endif // !defined(ANDROID_PLUGINS) + #endif diff --git a/WebCore/plugins/PluginPackage.cpp b/WebCore/plugins/PluginPackage.cpp deleted file mode 100644 index 76882c8..0000000 --- a/WebCore/plugins/PluginPackage.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. 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 "PluginPackage.h" - -#include "MIMETypeRegistry.h" -#include "PluginDebug.h" -#include "Timer.h" -#include "npruntime_impl.h" -#include <wtf/OwnArrayPtr.h> - -namespace WebCore { - -PluginPackage::~PluginPackage() -{ - ASSERT(!m_isLoaded); -} - -void PluginPackage::freeLibrarySoon() -{ - ASSERT(!m_freeLibraryTimer.isActive()); - ASSERT(m_module); - ASSERT(m_loadCount == 0); - - m_freeLibraryTimer.startOneShot(0); -} - -void PluginPackage::freeLibraryTimerFired(Timer<PluginPackage>*) -{ - ASSERT(m_module); - ASSERT(m_loadCount == 0); - - unloadModule(m_module); - m_module = 0; -} - -PluginPackage::PluginPackage(const String& path, const PlatformFileTime& lastModified) - : RefCounted<PluginPackage>(0) - , m_path(path) - , m_moduleVersion(0) - , m_module(0) - , m_lastModified(lastModified) - , m_isLoaded(false) - , m_loadCount(0) - , m_freeLibraryTimer(this, &PluginPackage::freeLibraryTimerFired) -{ - m_fileName = pathGetFileName(m_path); - m_parentDirectory = m_path.left(m_path.length() - m_fileName.length() - 1); -} - -void PluginPackage::unload() -{ - if (!m_isLoaded) - return; - - if (--m_loadCount > 0) - return; - - m_NPP_Shutdown(); - - unloadWithoutShutdown(); -} - -void PluginPackage::unloadWithoutShutdown() -{ - if (!m_isLoaded) - return; - - ASSERT(m_loadCount == 0); - ASSERT(m_module); - - // <rdar://5530519>: Crash when closing tab with pdf file (Reader 7 only) - // If the plugin has subclassed its parent window, as with Reader 7, we may have - // gotten here by way of the plugin's internal window proc forwarding a message to our - // original window proc. If we free the plugin library from here, we will jump back - // to code we just freed when we return, so delay calling FreeLibrary at least until - // the next message loop - freeLibrarySoon(); - - m_isLoaded = false; -} - -PluginPackage* PluginPackage::createPackage(const String& path, const PlatformFileTime& lastModified) -{ - PluginPackage* package = new PluginPackage(path, lastModified); - - if (!package->fetchInfo()) { - delete package; - return 0; - } - - return package; -} - -} diff --git a/WebCore/plugins/PluginPackage.h b/WebCore/plugins/PluginPackage.h index 7a46983..ab15e33 100644 --- a/WebCore/plugins/PluginPackage.h +++ b/WebCore/plugins/PluginPackage.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,11 +26,22 @@ #ifndef PluginPackage_H #define PluginPackage_H -#include "FileSystem.h" -#include "PlatformString.h" -#include "PluginQuirkSet.h" -#include "StringHash.h" +#ifdef ANDROID_PLUGINS + +#include "PluginPackageAndroid.h" + +namespace WebCore { + typedef PluginPackageAndroid PluginPackage; +} + +#else !defined(ANDROID_PLUGINS) + +#include <winsock2.h> +#include <windows.h> + #include "Timer.h" +#include "StringHash.h" +#include "PlatformString.h" #include "npfunctions.h" #include <wtf/HashMap.h> #include <wtf/RefCounted.h> @@ -43,7 +53,7 @@ namespace WebCore { class PluginPackage : public RefCounted<PluginPackage> { public: ~PluginPackage(); - static PluginPackage* createPackage(const String& path, const PlatformFileTime& lastModified); + static PluginPackage* createPackage(const String& path, const FILETIME& lastModified); String name() const { return m_name; } String description() const { return m_description; } @@ -53,7 +63,7 @@ namespace WebCore { const MIMEToDescriptionsMap& mimeToDescriptions() const { return m_mimeToDescriptions; } const MIMEToExtensionsMap& mimeToExtensions() const { return m_mimeToExtensions; } - unsigned hash() const; + unsigned PluginPackage::hash() const; static bool equal(const PluginPackage& a, const PluginPackage& b); bool load(); @@ -61,33 +71,31 @@ namespace WebCore { void unloadWithoutShutdown(); const NPPluginFuncs* pluginFuncs() const { return &m_pluginFuncs; } - int compareFileVersion(const PlatformModuleVersion&) const; - int compare(const PluginPackage&) const; - PluginQuirkSet quirks() const { return m_quirks; } - const PlatformModuleVersion& version() const { return m_moduleVersion; } + int compareFileVersion(unsigned compareVersionMS, unsigned compareVersionLS) const; private: - PluginPackage(const String& path, const PlatformFileTime& lastModified); + PluginPackage(const String& path, const FILETIME& lastModified); bool fetchInfo(); + void storeFileVersion(LPVOID versionInfoData); bool isPluginBlacklisted(); - void determineQuirks(const String& mimeType); bool m_isLoaded; int m_loadCount; + DWORD m_fileVersionMS; + DWORD m_fileVersionLS; + String m_description; String m_path; String m_fileName; String m_name; String m_parentDirectory; - PlatformModuleVersion m_moduleVersion; - MIMEToDescriptionsMap m_mimeToDescriptions; MIMEToExtensionsMap m_mimeToExtensions; - PlatformModule m_module; - PlatformFileTime m_lastModified; + HMODULE m_module; + FILETIME m_lastModified; NPP_ShutdownProcPtr m_NPP_Shutdown; NPPluginFuncs m_pluginFuncs; @@ -96,8 +104,6 @@ namespace WebCore { void freeLibrarySoon(); void freeLibraryTimerFired(Timer<PluginPackage>*); Timer<PluginPackage> m_freeLibraryTimer; - - PluginQuirkSet m_quirks; }; struct PluginPackageHash { @@ -121,5 +127,6 @@ namespace WTF { }; } +#endif // !defined(ANDROID_PLUGINS) #endif diff --git a/WebCore/plugins/PluginQuirkSet.h b/WebCore/plugins/PluginQuirkSet.h index e93f6e0..031baa0 100644 --- a/WebCore/plugins/PluginQuirkSet.h +++ b/WebCore/plugins/PluginQuirkSet.h @@ -44,7 +44,6 @@ namespace WebCore { PluginQuirkFlashURLNotifyBug = 1 << 8, PluginQuirkDontClipToZeroRectWhenScrolling = 1 << 9, PluginQuirkDontSetNullWindowHandleOnDestroy = 1 << 10, - PluginQuirkDontAllowMultipleInstances = 1 << 11, }; class PluginQuirkSet { diff --git a/WebCore/plugins/PluginStream.cpp b/WebCore/plugins/PluginStream.cpp index 0e6a445..a206b51 100644 --- a/WebCore/plugins/PluginStream.cpp +++ b/WebCore/plugins/PluginStream.cpp @@ -52,8 +52,7 @@ static StreamMap& streams() } PluginStream::PluginStream(PluginStreamClient* client, Frame* frame, const ResourceRequest& resourceRequest, bool sendNotification, void* notifyData, const NPPluginFuncs* pluginFuncs, NPP instance, const PluginQuirkSet& quirks) - : RefCounted<PluginStream>(0) - , m_resourceRequest(resourceRequest) + : m_resourceRequest(resourceRequest) , m_client(client) , m_frame(frame) , m_notifyData(notifyData) @@ -130,10 +129,14 @@ void PluginStream::startStream() // Some plugins (Flash) expect that javascript URLs are passed back decoded as this is the // format used when requesting the URL. +#ifdef ANDROID_JAVASCRIPT_SECURITY if (responseURL.protocolIs("javascript")) - m_stream.url = strdup(decodeURLEscapeSequences(responseURL.string()).utf8().data()); +#else + if (responseURL.string().startsWith("javascript:", false)) +#endif + m_stream.url = strdup(responseURL.decode_string(responseURL.deprecatedString()).utf8()); else - m_stream.url = strdup(responseURL.string().utf8().data()); + m_stream.url = strdup(responseURL.deprecatedString().utf8()); CString mimeTypeStr = m_resourceResponse.mimeType().utf8(); @@ -284,7 +287,7 @@ void PluginStream::destroyStream() // destructor, so reset it to 0 m_stream.url = 0; } - m_pluginFuncs->urlnotify(m_instance, m_resourceRequest.url().string().utf8().data(), m_reason, m_notifyData); + m_pluginFuncs->urlnotify(m_instance, m_resourceRequest.url().deprecatedString().utf8(), m_reason, m_notifyData); if (m_loader) m_loader->setDefersLoading(false); } diff --git a/WebCore/plugins/PluginStream.h b/WebCore/plugins/PluginStream.h index 921a50d..6eb7b81 100644 --- a/WebCore/plugins/PluginStream.h +++ b/WebCore/plugins/PluginStream.h @@ -27,6 +27,16 @@ #ifndef PluginStream_H #define PluginStream_H +#ifdef ANDROID_PLUGINS + +#include "PluginStreamAndroid.h" + +namespace WebCore { + typedef PluginStreamAndroid PluginStream; +} + +#else // !defined(ANDROID_PLUGINS) + #include "CString.h" #include "FileSystem.h" #include "KURL.h" @@ -113,4 +123,6 @@ namespace WebCore { } // namespace WebCore +#endif // !defined(ANDROID_PLUGINS) + #endif diff --git a/WebCore/plugins/PluginView.h b/WebCore/plugins/PluginView.h index 3e4fc10..9256256 100644 --- a/WebCore/plugins/PluginView.h +++ b/WebCore/plugins/PluginView.h @@ -27,6 +27,16 @@ #ifndef PluginView_H #define PluginView_H +#ifdef ANDROID_PLUGINS + +#include "PluginViewAndroid.h" + +namespace WebCore { + typedef PluginViewAndroid PluginView; +} + +#else // !defined(ANDROID_PLUGINS) + #include <winsock2.h> #include <windows.h> @@ -35,6 +45,7 @@ #include "KURL.h" #include "PlatformString.h" #include "PluginStream.h" +#include "PluginQuirkSet.h" #include "ResourceRequest.h" #include "Timer.h" #include "Widget.h" @@ -75,7 +86,7 @@ namespace WebCore { friend static LRESULT CALLBACK PluginViewWndProc(HWND, UINT, WPARAM, LPARAM); public: - static PluginView* create(Frame* parentFrame, const IntSize&, Element*, const KURL&, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually); + PluginView(Frame* parentFrame, const IntSize&, PluginPackage* plugin, Element*, const KURL&, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually); virtual ~PluginView(); PluginPackage* plugin() const { return m_plugin.get(); } @@ -137,8 +148,6 @@ namespace WebCore { static bool isCallingPlugin(); private: - PluginView(Frame* parentFrame, const IntSize&, PluginPackage*, Element*, const KURL&, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually); - void setParameters(const Vector<String>& paramNames, const Vector<String>& paramValues); void init(); bool start(); @@ -170,6 +179,7 @@ namespace WebCore { OwnPtr<PluginMessageThrottlerWin> m_messageThrottler; void updateWindow() const; + void determineQuirks(const String& mimeType); void paintMissingPluginIcon(GraphicsContext*, const IntRect&); void handleKeyboardEvent(KeyboardEvent*); @@ -192,6 +202,7 @@ namespace WebCore { HashSet<RefPtr<PluginStream> > m_streams; Vector<PluginRequest*> m_requests; + PluginQuirkSet m_quirks; bool m_isWindowed; bool m_isTransparent; bool m_isVisible; @@ -214,4 +225,6 @@ namespace WebCore { } // namespace WebCore +#endif // !defined(ANDROID_PLUGINS) + #endif 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 diff --git a/WebCore/plugins/win/PluginDatabaseWin.cpp b/WebCore/plugins/win/PluginDatabaseWin.cpp index 674de1e..be8a253 100644 --- a/WebCore/plugins/win/PluginDatabaseWin.cpp +++ b/WebCore/plugins/win/PluginDatabaseWin.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,14 +26,99 @@ #include "config.h" #include "PluginDatabase.h" -#include "Frame.h" -#include "KURL.h" #include "PluginPackage.h" +#include "PluginView.h" +#include "Frame.h" #include <windows.h> #include <shlwapi.h> namespace WebCore { +PluginDatabase* PluginDatabase::installedPlugins() +{ + static PluginDatabase* plugins = 0; + + if (!plugins) { + plugins = new PluginDatabase; + plugins->setPluginPaths(PluginDatabase::defaultPluginPaths()); + plugins->refresh(); + } + + return plugins; +} + +void PluginDatabase::addExtraPluginPath(const String& path) +{ + m_pluginPaths.append(path); + refresh(); +} + +bool PluginDatabase::refresh() +{ + PluginSet newPlugins; + + bool pluginSetChanged = false; + + // Create a new set of plugins + newPlugins = getPluginsInPaths(); + + if (!m_plugins.isEmpty()) { + m_registeredMIMETypes.clear(); + + PluginSet pluginsToUnload = m_plugins; + + PluginSet::const_iterator end = newPlugins.end(); + for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it) + pluginsToUnload.remove(*it); + + end = m_plugins.end(); + for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) + newPlugins.remove(*it); + + // Unload plugins + end = pluginsToUnload.end(); + for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it) + m_plugins.remove(*it); + + // Add new plugins + end = newPlugins.end(); + for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it) + m_plugins.add(*it); + + pluginSetChanged = !pluginsToUnload.isEmpty() || !newPlugins.isEmpty(); + } else { + m_plugins = newPlugins; + PluginSet::const_iterator end = newPlugins.end(); + for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it) + m_plugins.add(*it); + + pluginSetChanged = !newPlugins.isEmpty(); + } + + // Register plug-in MIME types + PluginSet::const_iterator end = m_plugins.end(); + for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { + // Get MIME types + MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end(); + for (MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin(); map_it != map_end; ++map_it) { + m_registeredMIMETypes.add(map_it->first); + } + } + + return pluginSetChanged; +} + +Vector<PluginPackage*> PluginDatabase::plugins() const +{ + Vector<PluginPackage*> result; + + PluginSet::const_iterator end = m_plugins.end(); + for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) + result.append((*it).get()); + + return result; +} + static inline void addPluginsFromRegistry(HKEY rootKey, PluginSet& plugins) { HKEY key; @@ -351,14 +435,106 @@ Vector<String> PluginDatabase::defaultPluginPaths() return paths; } -bool PluginDatabase::isPreferredPluginPath(const String& path) +bool PluginDatabase::isMIMETypeRegistered(const String& mimeType) +{ + if (mimeType.isNull()) + return false; + if (m_registeredMIMETypes.contains(mimeType)) + return true; + // No plugin was found, try refreshing the database and searching again + return (refresh() && m_registeredMIMETypes.contains(mimeType)); +} + +PluginPackage* PluginDatabase::pluginForMIMEType(const String& mimeType) { + if (mimeType.isEmpty()) + return 0; + + String key = mimeType.lower(); String ourPath = safariPluginsPath(); + PluginPackage* plugin = 0; + PluginSet::const_iterator end = m_plugins.end(); + + for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { + if ((*it)->mimeToDescriptions().contains(key)) { + plugin = (*it).get(); + // prefer plugins in our own plugins directory + if (plugin->parentDirectory() == ourPath) + break; + } + } - if (!ourPath.isNull() && !path.isNull()) - return ourPath == path; + return plugin; +} - return false; +String PluginDatabase::MIMETypeForExtension(const String& extension) const +{ + if (extension.isEmpty()) + return String(); + + PluginSet::const_iterator end = m_plugins.end(); + String ourPath = safariPluginsPath(); + String mimeType; + PluginPackage* plugin = 0; + + for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { + MIMEToExtensionsMap::const_iterator mime_end = (*it)->mimeToExtensions().end(); + + for (MIMEToExtensionsMap::const_iterator mime_it = (*it)->mimeToExtensions().begin(); mime_it != mime_end; ++mime_it) { + const Vector<String>& extensions = mime_it->second; + for (unsigned i = 0; i < extensions.size(); i++) { + if (equalIgnoringCase(extensions[i], extension)) { + mimeType = mime_it->first; + plugin = (*it).get(); + // prefer plugins in our own plugins directory + if (plugin->parentDirectory() == ourPath) + break; + } + } + } + } + + return mimeType; +} + +PluginPackage* PluginDatabase::findPlugin(const KURL& url, String& mimeType) +{ + PluginPackage* 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); + plugin = pluginForMIMEType(mimeType); + } + } + } + + // FIXME: if no plugin could be found, query Windows for the mime type + // corresponding to the extension. + + return plugin; +} + +PluginView* PluginDatabase::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; + PluginPackage* 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 PluginView(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually); } } diff --git a/WebCore/plugins/win/PluginPackageWin.cpp b/WebCore/plugins/win/PluginPackageWin.cpp index ccc7586..c744822 100644 --- a/WebCore/plugins/win/PluginPackageWin.cpp +++ b/WebCore/plugins/win/PluginPackageWin.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * 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 @@ -29,76 +28,124 @@ #include "config.h" #include "PluginPackage.h" -#include "CString.h" -#include "MIMETypeRegistry.h" -#include "PluginDatabase.h" -#include "PluginDebug.h" #include "Timer.h" +#include "DeprecatedString.h" #include "npruntime_impl.h" -#include <string.h> -#include <wtf/OwnArrayPtr.h> +#include "PluginDebug.h" namespace WebCore { +PluginPackage::~PluginPackage() +{ + ASSERT(!m_isLoaded); +} + static String getVersionInfo(const LPVOID versionInfoData, const String& info) { LPVOID buffer; UINT bufferLength; String subInfo = "\\StringfileInfo\\040904E4\\" + info; - bool retval = VerQueryValueW(versionInfoData, - const_cast<UChar*>(subInfo.charactersWithNullTermination()), - &buffer, &bufferLength); + + bool retval = VerQueryValueW(versionInfoData, const_cast<UChar*>(subInfo.charactersWithNullTermination()), + &buffer, &bufferLength); if (!retval || bufferLength == 0) return String(); - // Subtract 1 from the length; we don't want the trailing null character. + // Subtract 1 from the length; we don't want the trailing 0 return String(reinterpret_cast<UChar*>(buffer), bufferLength - 1); } -int PluginPackage::compareFileVersion(const PlatformModuleVersion& compareVersion) const +static Vector<String> splitString(const String& str, char delimiter, int padTo) +{ + int pos = 0; + int newPos; + Vector<String> result; + DeprecatedString ds = str.deprecatedString(); + String s; + do { + + newPos = ds.find(delimiter, pos); + + if (newPos == -1) + s = ds.mid(pos); + else + s = ds.mid(pos, newPos - pos); + + if (!s.isEmpty()) + result.append(s); + + pos = newPos + 1; + } while (newPos != -1); + + while (padTo != -1 && static_cast<int>(result.size()) < padTo) + result.append(""); + + return result; +} + +void PluginPackage::freeLibrarySoon() +{ + ASSERT(!m_freeLibraryTimer.isActive()); + ASSERT(m_module); + ASSERT(m_loadCount == 0); + + m_freeLibraryTimer.startOneShot(0); +} + +void PluginPackage::freeLibraryTimerFired(Timer<PluginPackage>* /*timer*/) +{ + ASSERT(m_module); + ASSERT(m_loadCount == 0); + + ::FreeLibrary(m_module); + m_module = 0; +} + +PluginPackage::PluginPackage(const String& path, const FILETIME& lastModified) + : m_path(path) + , m_module(0) + , m_lastModified(lastModified) + , m_isLoaded(false) + , m_loadCount(0) + , m_freeLibraryTimer(this, &PluginPackage::freeLibraryTimerFired) + , m_fileVersionLS(0) + , m_fileVersionMS(0) +{ + m_fileName = String(PathFindFileName(m_path.charactersWithNullTermination())); + m_parentDirectory = m_path.left(m_path.length() - m_fileName.length() - 1); +} + +int PluginPackage::compareFileVersion(unsigned compareVersionMS, unsigned compareVersionLS) const { // return -1, 0, or 1 if plug-in version is less than, equal to, or greater than // the passed version - if (m_moduleVersion.mostSig != compareVersion.mostSig) - return m_moduleVersion.mostSig > compareVersion.mostSig ? 1 : -1; - if (m_moduleVersion.leastSig != compareVersion.leastSig) - return m_moduleVersion.leastSig > compareVersion.leastSig ? 1 : -1; + if (m_fileVersionMS != compareVersionMS) + return m_fileVersionMS > compareVersionMS ? 1 : -1; + if (m_fileVersionLS != compareVersionLS) + return m_fileVersionLS > compareVersionLS ? 1 : -1; return 0; } -int PluginPackage::compare(const PluginPackage& compareTo) const +void PluginPackage::storeFileVersion(LPVOID versionInfoData) { - // Sort plug-ins that allow multiple instances first. - bool AallowsMultipleInstances = !quirks().contains(PluginQuirkDontAllowMultipleInstances); - bool BallowsMultipleInstances = !compareTo.quirks().contains(PluginQuirkDontAllowMultipleInstances); - if (AallowsMultipleInstances != BallowsMultipleInstances) - return AallowsMultipleInstances ? -1 : 1; - - // Sort plug-ins in a preferred path first. - bool AisInPreferredPath = PluginDatabase::isPreferredPluginPath(parentDirectory()); - bool BisInPreferredPath = PluginDatabase::isPreferredPluginPath(compareTo.parentDirectory()); - if (AisInPreferredPath != BisInPreferredPath) - return AisInPreferredPath ? -1 : 1; - - int diff = strcmp(name().utf8().data(), compareTo.name().utf8().data()); - if (diff) - return diff; - - if (diff = compareFileVersion(compareTo.version())) - return diff; - - return strcmp(parentDirectory().utf8().data(), compareTo.parentDirectory().utf8().data()); + VS_FIXEDFILEINFO* info; + UINT infoSize; + if (!VerQueryValue(versionInfoData, TEXT("\\"), (LPVOID*) &info, &infoSize) || infoSize < sizeof(VS_FIXEDFILEINFO)) + return; + m_fileVersionLS = info->dwFileVersionLS; + m_fileVersionMS = info->dwFileVersionMS; } bool PluginPackage::isPluginBlacklisted() { - static const PlatformModuleVersion slPluginMinRequired(0x51BE0000, 0x00010000); + static const unsigned silverlightPluginMinRequiredVersionMS = 0x00010000; + static const unsigned silverlightPluginMinRequiredVersionLS = 0x51BE0000; if (name() == "Silverlight Plug-In") { // workaround for <rdar://5557379> Crash in Silverlight when opening microsoft.com. // the latest 1.0 version of Silverlight does not reproduce this crash, so allow it // and any newer versions - if (compareFileVersion(slPluginMinRequired) < 0) + if (compareFileVersion(silverlightPluginMinRequiredVersionMS, silverlightPluginMinRequiredVersionLS) < 0) return true; } else if (fileName() == "npmozax.dll") // Bug 15217: Mozilla ActiveX control complains about missing xpcom_core.dll @@ -107,134 +154,58 @@ bool PluginPackage::isPluginBlacklisted() return false; } -void PluginPackage::determineQuirks(const String& mimeType) -{ - static const PlatformModuleVersion lastKnownUnloadableRealPlayerVersion(0x000B0B24, 0x00060000); - - if (mimeType == "application/x-shockwave-flash") { - // The flash plugin only requests windowless plugins if we return a mozilla user agent - m_quirks.add(PluginQuirkWantsMozillaUserAgent); - m_quirks.add(PluginQuirkThrottleInvalidate); - m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages); - m_quirks.add(PluginQuirkFlashURLNotifyBug); - } - - if (name().contains("Microsoft") && name().contains("Windows Media")) { - // The WMP plugin sets its size on the first NPP_SetWindow call and never updates its size, so - // call SetWindow when the plugin view has a correct size - m_quirks.add(PluginQuirkDeferFirstSetWindowCall); - - // Windowless mode does not work at all with the WMP plugin so just remove that parameter - // and don't pass it to the plug-in. - m_quirks.add(PluginQuirkRemoveWindowlessVideoParam); - - // WMP has a modal message loop that it enters whenever we call it or - // ask it to paint. This modal loop can deliver messages to other - // windows in WebKit at times when they are not expecting them (for - // example, delivering a WM_PAINT message during a layout), and these - // can cause crashes. - m_quirks.add(PluginQuirkHasModalMessageLoop); - } - - if (name() == "VLC Multimedia Plugin") { - // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window handle - m_quirks.add(PluginQuirkDontSetNullWindowHandleOnDestroy); - - // VLC 0.8.6d and 0.8.6e crash if multiple instances are created. - // <rdar://problem/5773070> tracks allowing multiple instances when this - // bug is fixed. - m_quirks.add(PluginQuirkDontAllowMultipleInstances); - } - - // The DivX plugin sets its size on the first NPP_SetWindow call and never updates its size, so - // call SetWindow when the plugin view has a correct size - if (mimeType == "video/divx") - m_quirks.add(PluginQuirkDeferFirstSetWindowCall); - - // FIXME: This is a workaround for a problem in our NPRuntime bindings; if a plug-in creates an - // NPObject and passes it to a function it's not possible to see what root object that NPObject belongs to. - // Thus, we don't know that the object should be invalidated when the plug-in instance goes away. - // See <rdar://problem/5487742>. - if (mimeType == "application/x-silverlight") - m_quirks.add(PluginQuirkDontUnloadPlugin); - - if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) { - // Because a single process cannot create multiple VMs, and we cannot reliably unload a - // Java VM, we cannot unload the Java plugin, or we'll lose reference to our only VM - m_quirks.add(PluginQuirkDontUnloadPlugin); - - // Setting the window region to an empty region causes bad scrolling repaint problems - // with the Java plug-in. - m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling); - } - - if (mimeType == "audio/x-pn-realaudio-plugin") { - // Prevent the Real plugin from calling the Window Proc recursively, causing the stack to overflow. - m_quirks.add(PluginQuirkDontCallWndProcForSameMessageRecursively); - - // Unloading RealPlayer versions newer than 10.5 can cause a hang; see rdar://5669317. - // FIXME: Resume unloading when this bug in the RealPlayer Plug-In is fixed (rdar://5713147) - if (compareFileVersion(lastKnownUnloadableRealPlayerVersion) > 0) - m_quirks.add(PluginQuirkDontUnloadPlugin); - } -} - bool PluginPackage::fetchInfo() { DWORD versionInfoSize, zeroHandle; versionInfoSize = GetFileVersionInfoSizeW(m_path.charactersWithNullTermination(), &zeroHandle); + if (versionInfoSize == 0) return false; - OwnArrayPtr<char> versionInfoData(new char[versionInfoSize]); + LPVOID versionInfoData = fastMalloc(versionInfoSize); - if (!GetFileVersionInfoW(m_path.charactersWithNullTermination(), 0, versionInfoSize, versionInfoData.get())) + if (!GetFileVersionInfoW(m_path.charactersWithNullTermination(), 0, versionInfoSize, versionInfoData)) { + fastFree(versionInfoData); return false; + } - m_name = getVersionInfo(versionInfoData.get(), "ProductName"); - m_description = getVersionInfo(versionInfoData.get(), "FileDescription"); - if (m_name.isNull() || m_description.isNull()) - return false; + m_name = getVersionInfo(versionInfoData, "ProductName"); + m_description = getVersionInfo(versionInfoData, "FileDescription"); - VS_FIXEDFILEINFO* info; - UINT infoSize; - if (!VerQueryValue(versionInfoData.get(), TEXT("\\"), (LPVOID*) &info, &infoSize) || infoSize < sizeof(VS_FIXEDFILEINFO)) + if (m_name.isNull() || m_description.isNull()) { + fastFree(versionInfoData); return false; - m_moduleVersion.leastSig = info->dwFileVersionLS; - m_moduleVersion.mostSig = info->dwFileVersionMS; + } - if (isPluginBlacklisted()) - return false; + storeFileVersion(versionInfoData); - Vector<String> types; - getVersionInfo(versionInfoData.get(), "MIMEType").split('|', types); - Vector<String> extensionLists; - getVersionInfo(versionInfoData.get(), "FileExtents").split('|', extensionLists); - Vector<String> descriptions; - getVersionInfo(versionInfoData.get(), "FileOpenName").split('|', descriptions); + if (isPluginBlacklisted()) { + fastFree(versionInfoData); + return false; + } - for (unsigned i = 0; i < types.size(); i++) { - String type = types[i].lower(); - String description = i < descriptions.size() ? descriptions[i] : ""; - String extensionList = i < extensionLists.size() ? extensionLists[i] : ""; + Vector<String> mimeTypes = splitString(getVersionInfo(versionInfoData, "MIMEType"), '|', -1); + Vector<String> fileExtents = splitString(getVersionInfo(versionInfoData, "FileExtents"), '|', mimeTypes.size()); + Vector<String> descriptions = splitString(getVersionInfo(versionInfoData, "FileOpenName"), '|', mimeTypes.size()); - Vector<String> extensionsVector; - extensionList.split(',', extensionsVector); + fastFree(versionInfoData); - // Get rid of the extension list that may be at the end of the description string. + for (unsigned i = 0; i < mimeTypes.size(); i++) { + // Get rid of the extension list in the description string + String description = descriptions[i]; int pos = description.find("(*"); if (pos != -1) { - // There might be a space that we need to get rid of. + // There might be a space that we need to get rid of if (pos > 1 && description[pos - 1] == ' ') pos--; + description = description.left(pos); } - // Determine the quirks for the MIME types this plug-in supports - determineQuirks(type); + mimeTypes[i] = mimeTypes[i].lower(); - m_mimeToExtensions.add(type, extensionsVector); - m_mimeToDescriptions.add(type, description); + m_mimeToExtensions.add(mimeTypes[i], splitString(fileExtents[i], ',', -1)); + m_mimeToDescriptions.add(mimeTypes[i], description); } return true; @@ -246,8 +217,6 @@ bool PluginPackage::load() ASSERT(m_module); m_freeLibraryTimer.stop(); } else if (m_isLoaded) { - if (m_quirks.contains(PluginQuirkDontAllowMultipleInstances)) - return false; m_loadCount++; return true; } else { @@ -298,7 +267,6 @@ bool PluginPackage::load() 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; @@ -352,21 +320,64 @@ bool PluginPackage::load() m_loadCount++; return true; - abort: unloadWithoutShutdown(); return false; } +void PluginPackage::unload() +{ + if (!m_isLoaded) + return; + + if (--m_loadCount > 0) + return; + + m_NPP_Shutdown(); + + unloadWithoutShutdown(); +} + +void PluginPackage::unloadWithoutShutdown() +{ + if (!m_isLoaded) + return; + + ASSERT(m_loadCount == 0); + ASSERT(m_module); + + // <rdar://5530519>: Crash when closing tab with pdf file (Reader 7 only) + // If the plugin has subclassed its parent window, as with Reader 7, we may have + // gotten here by way of the plugin's internal window proc forwarding a message to our + // original window proc. If we free the plugin library from here, we will jump back + // to code we just freed when we return, so delay calling FreeLibrary at least until + // the next message loop + freeLibrarySoon(); + + m_isLoaded = false; +} + +PluginPackage* PluginPackage::createPackage(const String& path, const FILETIME& lastModified) +{ + PluginPackage* package = new PluginPackage(path, lastModified); + + if (!package->fetchInfo()) { + delete package; + return 0; + } + + return package; +} + unsigned PluginPackage::hash() const { - const unsigned hashCodes[3] = { + unsigned hashCodes[3] = { m_description.impl()->hash(), m_lastModified.dwLowDateTime, m_lastModified.dwHighDateTime }; - return StringImpl::computeHash(reinterpret_cast<const UChar*>(hashCodes), 3 * sizeof(unsigned) / sizeof(UChar)); + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 3 * sizeof(unsigned) / sizeof(UChar)); } bool PluginPackage::equal(const PluginPackage& a, const PluginPackage& b) diff --git a/WebCore/plugins/win/PluginViewWin.cpp b/WebCore/plugins/win/PluginViewWin.cpp index 4275b2c..b219fa5 100644 --- a/WebCore/plugins/win/PluginViewWin.cpp +++ b/WebCore/plugins/win/PluginViewWin.cpp @@ -51,7 +51,6 @@ #include "kjs_binding.h" #include "kjs_proxy.h" #include "kjs_window.h" -#include "PluginDatabase.h" #include "PluginDebug.h" #include "PluginPackage.h" #include "npruntime_impl.h" @@ -208,11 +207,11 @@ private: static String scriptStringIfJavaScriptURL(const KURL& url) { - if (!url.protocolIs("javascript")) + if (!url.string().startsWith("javascript:", false)) return String(); // This returns an unescaped string - return decodeURLEscapeSequences(url.string().substring(11)); + return KURL::decode_string(url.deprecatedString().mid(11)); } PluginView* PluginView::s_currentPluginView = 0; @@ -300,12 +299,12 @@ PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } if (message == m_lastMessage && - m_plugin->quirks().contains(PluginQuirkDontCallWndProcForSameMessageRecursively) && + m_quirks.contains(PluginQuirkDontCallWndProcForSameMessageRecursively) && m_isCallingPluginWndProc) return 1; if (message == WM_USER + 1 && - m_plugin->quirks().contains(PluginQuirkThrottleWMUserPlusOneMessages)) { + m_quirks.contains(PluginQuirkThrottleWMUserPlusOneMessages)) { if (!m_messageThrottler) m_messageThrottler.set(new PluginMessageThrottlerWin(this)); @@ -359,7 +358,7 @@ void PluginView::updateWindow() const // To prevent flashes while scrolling, we disable drawing during the window // update process by clipping the window to the zero rect. - bool clipToZeroRect = !m_plugin->quirks().contains(PluginQuirkDontClipToZeroRectWhenScrolling); + bool clipToZeroRect = !m_quirks.contains(PluginQuirkDontClipToZeroRectWhenScrolling); if (clipToZeroRect) { rgn = ::CreateRectRgn(0, 0, 0, 0); @@ -785,7 +784,7 @@ void PluginView::stop() // Clear the window m_npWindow.window = 0; - if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) { + if (m_plugin->pluginFuncs()->setwindow && !m_quirks.contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) { setCallingPlugin(true); m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); setCallingPlugin(false); @@ -868,7 +867,7 @@ void PluginView::performRequest(PluginRequest* request) // if this is not a targeted request, create a stream for it. otherwise, // just pass it off to the loader if (targetFrameName.isEmpty()) { - PluginStream* stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks()); + PluginStream* stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_quirks); m_streams.add(stream); stream->start(); } else { @@ -878,7 +877,7 @@ void PluginView::performRequest(PluginRequest* request) if (request->sendNotification()) { KJS::JSLock::DropAllLocks dropAllLocks; setCallingPlugin(true); - m_plugin->pluginFuncs()->urlnotify(m_instance, requestURL.string().utf8().data(), NPRES_DONE, request->notifyData()); + m_plugin->pluginFuncs()->urlnotify(m_instance, requestURL.deprecatedString().utf8(), NPRES_DONE, request->notifyData()); setCallingPlugin(false); } } @@ -900,7 +899,7 @@ void PluginView::performRequest(PluginRequest* request) if (getString(parentFrame->scriptProxy(), result, resultString)) cstr = resultString.utf8(); - RefPtr<PluginStream> stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks()); + RefPtr<PluginStream> stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_quirks); m_streams.add(stream); stream->sendJavaScriptStream(requestURL, cstr); } @@ -962,9 +961,9 @@ NPError PluginView::load(const FrameLoadRequest& frameLoadRequest, bool sendNoti static KURL makeURL(const KURL& baseURL, const char* relativeURLString) { - String urlString = relativeURLString; + DeprecatedString urlString = DeprecatedString::fromLatin1(relativeURLString); - // Strip return characters. + // Strip return characters urlString.replace('\n', ""); urlString.replace('\r', ""); @@ -1108,7 +1107,7 @@ static inline HTTPHeaderMap parseRFC822HeaderFields(const Vector<char>& buffer, } else { // Merge the continuation of the previous header String currentValue = headerFields.get(lastKey); - String newValue(line, lineLength); + String newValue = DeprecatedString::fromLatin1(line, lineLength); headerFields.set(lastKey, currentValue + newValue); } @@ -1122,7 +1121,7 @@ static inline HTTPHeaderMap parseRFC822HeaderFields(const Vector<char>& buffer, // malformed header; ignore it and continue continue; else { - lastKey = capitalizeRFC822HeaderFieldName(String(line, colon - line)); + lastKey = capitalizeRFC822HeaderFieldName(DeprecatedString::fromLatin1(line, colon - line)); String value; for (colon++; colon != eol; colon++) { @@ -1132,7 +1131,7 @@ static inline HTTPHeaderMap parseRFC822HeaderFields(const Vector<char>& buffer, if (colon == eol) value = ""; else - value = String(colon, eol - colon); + value = DeprecatedString::fromLatin1(colon, eol - colon); String oldValue = headerFields.get(lastKey); if (!oldValue.isNull()) { @@ -1161,7 +1160,7 @@ NPError PluginView::handlePost(const char* url, const char* target, uint32 len, Vector<char> buffer; if (file) { - String filename(buf, len); + String filename = DeprecatedString::fromLatin1(buf, len); if (filename.startsWith("file:///")) filename = filename.substring(8); @@ -1225,7 +1224,7 @@ NPError PluginView::handlePost(const char* url, const char* target, uint32 len, frameLoadRequest.resourceRequest().setHTTPMethod("POST"); frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url)); frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields); - frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(postData, postDataLength)); + frameLoadRequest.resourceRequest().setHTTPBody(PassRefPtr<FormData>(new FormData(postData, postDataLength))); frameLoadRequest.setFrameName(target); return load(frameLoadRequest, sendNotification, notifyData); @@ -1269,7 +1268,7 @@ NPError PluginView::destroyStream(NPStream* stream, NPReason reason) const char* PluginView::userAgent() { - if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent)) + if (m_quirks.contains(PluginQuirkWantsMozillaUserAgent)) return MozillaUserAgent; if (m_userAgent.isNull()) @@ -1279,8 +1278,10 @@ const char* PluginView::userAgent() void PluginView::status(const char* message) { + String s = DeprecatedString::fromLatin1(message); + if (Page* page = m_parentFrame->page()) - page->chrome()->setStatusbarText(m_parentFrame, String(message)); + page->chrome()->setStatusbarText(m_parentFrame, s); } NPError PluginView::getValue(NPNVariable variable, void* value) @@ -1365,7 +1366,7 @@ void PluginView::invalidateRect(NPRect* rect) RECT invalidRect(r); InvalidateRect(m_window, &invalidRect, FALSE); } else { - if (m_plugin->quirks().contains(PluginQuirkThrottleInvalidate)) { + if (m_quirks.contains(PluginQuirkThrottleInvalidate)) { m_invalidRects.append(r); if (!m_invalidateTimer.isActive()) m_invalidateTimer.startOneShot(0.001); @@ -1455,7 +1456,7 @@ PluginView::~PluginView() m_parentFrame->cleanupScriptObjectsForPlugin(this); - if (m_plugin && !m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin)) + if (m_plugin && !m_quirks.contains(PluginQuirkDontUnloadPlugin)) m_plugin->unload(); } @@ -1466,6 +1467,73 @@ void PluginView::disconnectStream(PluginStream* stream) m_streams.remove(stream); } +void PluginView::determineQuirks(const String& mimeType) +{ + static const unsigned lastKnownUnloadableRealPlayerVersionLS = 0x000B0B24; + static const unsigned lastKnownUnloadableRealPlayerVersionMS = 0x00060000; + + if (mimeType == "application/x-shockwave-flash") { + // The flash plugin only requests windowless plugins if we return a mozilla user agent + m_quirks.add(PluginQuirkWantsMozillaUserAgent); + m_quirks.add(PluginQuirkThrottleInvalidate); + m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages); + m_quirks.add(PluginQuirkFlashURLNotifyBug); + } + + if (m_plugin->name().contains("Microsoft") && m_plugin->name().contains("Windows Media")) { + // The WMP plugin sets its size on the first NPP_SetWindow call and never updates its size, so + // call SetWindow when the plugin view has a correct size + m_quirks.add(PluginQuirkDeferFirstSetWindowCall); + + // Windowless mode does not work at all with the WMP plugin so just remove that parameter + // and don't pass it to the plug-in. + m_quirks.add(PluginQuirkRemoveWindowlessVideoParam); + + // WMP has a modal message loop that it enters whenever we call it or + // ask it to paint. This modal loop can deliver messages to other + // windows in WebKit at times when they are not expecting them (for + // example, delivering a WM_PAINT message during a layout), and these + // can cause crashes. + m_quirks.add(PluginQuirkHasModalMessageLoop); + } + + // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window handle + if (m_plugin->name() == "VLC Multimedia Plugin") + m_quirks.add(PluginQuirkDontSetNullWindowHandleOnDestroy); + + // The DivX plugin sets its size on the first NPP_SetWindow call and never updates its size, so + // call SetWindow when the plugin view has a correct size + if (mimeType == "video/divx") + m_quirks.add(PluginQuirkDeferFirstSetWindowCall); + + // FIXME: This is a workaround for a problem in our NPRuntime bindings; if a plug-in creates an + // NPObject and passes it to a function it's not possible to see what root object that NPObject belongs to. + // Thus, we don't know that the object should be invalidated when the plug-in instance goes away. + // See <rdar://problem/5487742>. + if (mimeType == "application/x-silverlight") + m_quirks.add(PluginQuirkDontUnloadPlugin); + + if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) { + // Because a single process cannot create multiple VMs, and we cannot reliably unload a + // Java VM, we cannot unload the Java plugin, or we'll lose reference to our only VM + m_quirks.add(PluginQuirkDontUnloadPlugin); + + // Setting the window region to an empty region causes bad scrolling repaint problems + // with the Java plug-in. + m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling); + } + + if (mimeType == "audio/x-pn-realaudio-plugin") { + // Prevent the Real plugin from calling the Window Proc recursively, causing the stack to overflow. + m_quirks.add(PluginQuirkDontCallWndProcForSameMessageRecursively); + + // Unloading RealPlayer versions newer than 10.5 can cause a hang; see rdar://5669317. + // FIXME: Resume unloading when this bug in the RealPlayer Plug-In is fixed (rdar://5713147) + if (m_plugin->compareFileVersion(lastKnownUnloadableRealPlayerVersionMS, lastKnownUnloadableRealPlayerVersionLS) > 0) + m_quirks.add(PluginQuirkDontUnloadPlugin); + } +} + void PluginView::setParameters(const Vector<String>& paramNames, const Vector<String>& paramValues) { ASSERT(paramNames.size() == paramValues.size()); @@ -1477,7 +1545,7 @@ void PluginView::setParameters(const Vector<String>& paramNames, const Vector<St m_paramValues = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size)); for (unsigned i = 0; i < size; i++) { - if (m_plugin->quirks().contains(PluginQuirkRemoveWindowlessVideoParam) && equalIgnoringCase(paramNames[i], "windowlessvideo")) + if (m_quirks.contains(PluginQuirkRemoveWindowlessVideoParam) && equalIgnoringCase(paramNames[i], "windowlessvideo")) continue; m_paramNames[paramCount] = createUTF8String(paramNames[i]); @@ -1495,7 +1563,7 @@ PluginView::PluginView(Frame* parentFrame, const IntSize& size, PluginPackage* p , m_element(element) , m_isStarted(false) , m_url(url) - , m_baseURL(m_parentFrame->loader()->completeURL(m_parentFrame->document()->baseURL().string())) + , m_baseURL(m_parentFrame->loader()->completeURL(m_parentFrame->document()->baseURL())) , m_status(PluginStatusLoadedSuccessfully) , m_requestTimer(this, &PluginView::requestTimerFired) , m_invalidateTimer(this, &PluginView::invalidateTimerFired) @@ -1523,6 +1591,7 @@ PluginView::PluginView(Frame* parentFrame, const IntSize& size, PluginPackage* p m_instance->ndata = this; m_mimeType = mimeType.utf8(); + determineQuirks(mimeType); setParameters(paramNames, paramValues); @@ -1576,7 +1645,7 @@ void PluginView::init() m_npWindow.window = 0; } - if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall)) + if (!m_quirks.contains(PluginQuirkDeferFirstSetWindowCall)) setNPWindowRect(frameGeometry()); m_status = PluginStatusLoadedSuccessfully; @@ -1587,7 +1656,7 @@ void PluginView::didReceiveResponse(const ResourceResponse& response) ASSERT(m_loadManually); ASSERT(!m_manualStream); - m_manualStream = new PluginStream(this, m_parentFrame, m_parentFrame->loader()->activeDocumentLoader()->request(), false, 0, plugin()->pluginFuncs(), instance(), m_plugin->quirks()); + m_manualStream = new PluginStream(this, m_parentFrame, m_parentFrame->loader()->activeDocumentLoader()->request(), false, 0, plugin()->pluginFuncs(), instance(), m_quirks); m_manualStream->setLoadManually(true); m_manualStream->didReceiveResponse(0, response); @@ -1619,7 +1688,7 @@ void PluginView::didFail(const ResourceError& error) void PluginView::setCallingPlugin(bool b) const { - if (!m_plugin->quirks().contains(PluginQuirkHasModalMessageLoop)) + if (!m_quirks.contains(PluginQuirkHasModalMessageLoop)) return; if (b) @@ -1635,20 +1704,4 @@ bool PluginView::isCallingPlugin() return s_callingPlugin > 0; } -PluginView* PluginView::create(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; - PluginPackage* plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy); - - // No plugin was found, try refreshing the database and searching again - if (!plugin && PluginDatabase::installedPlugins()->refresh()) { - mimeTypeCopy = mimeType; - plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy); - } - - return new PluginView(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually); -} - } // namespace WebCore |