summaryrefslogtreecommitdiffstats
path: root/WebCore/plugins/win
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/plugins/win')
-rw-r--r--WebCore/plugins/win/PluginDataWin.cpp72
-rw-r--r--WebCore/plugins/win/PluginDatabaseWin.cpp354
-rw-r--r--WebCore/plugins/win/PluginMessageThrottlerWin.cpp123
-rw-r--r--WebCore/plugins/win/PluginMessageThrottlerWin.h72
-rw-r--r--WebCore/plugins/win/PluginPackageWin.cpp374
-rw-r--r--WebCore/plugins/win/PluginViewWin.cpp861
6 files changed, 1856 insertions, 0 deletions
diff --git a/WebCore/plugins/win/PluginDataWin.cpp b/WebCore/plugins/win/PluginDataWin.cpp
new file mode 100644
index 0000000..4ec4b6d
--- /dev/null
+++ b/WebCore/plugins/win/PluginDataWin.cpp
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "PluginData.h"
+
+#include "PluginDatabase.h"
+#include "PluginPackage.h"
+
+namespace WebCore {
+
+void PluginData::initPlugins()
+{
+ PluginDatabase *db = PluginDatabase::installedPlugins();
+ const Vector<PluginPackage*> &plugins = db->plugins();
+
+ for (unsigned int i = 0; i < plugins.size(); ++i) {
+ PluginInfo* info = new PluginInfo;
+ PluginPackage* package = 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];
+ }
+ }
+
+ m_plugins.append(info);
+ }
+}
+
+void PluginData::refresh()
+{
+ PluginDatabase *db = PluginDatabase::installedPlugins();
+ db->refresh();
+}
+
+};
diff --git a/WebCore/plugins/win/PluginDatabaseWin.cpp b/WebCore/plugins/win/PluginDatabaseWin.cpp
new file mode 100644
index 0000000..c59f133
--- /dev/null
+++ b/WebCore/plugins/win/PluginDatabaseWin.cpp
@@ -0,0 +1,354 @@
+/*
+ * 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 <windows.h>
+#include <shlwapi.h>
+
+#if COMPILER(MINGW)
+#define _countof(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+namespace WebCore {
+
+static inline void addPluginPathsFromRegistry(HKEY rootKey, HashSet<String>& paths)
+{
+ HKEY key;
+ HRESULT result = RegOpenKeyExW(rootKey, L"Software\\MozillaPlugins", 0, KEY_ENUMERATE_SUB_KEYS, &key);
+
+ if (result != ERROR_SUCCESS)
+ return;
+
+ wchar_t name[128];
+ FILETIME lastModified;
+
+ // Enumerate subkeys
+ for (int i = 0;; i++) {
+ DWORD nameLen = _countof(name);
+ result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
+
+ if (result != ERROR_SUCCESS)
+ break;
+
+ WCHAR pathStr[_MAX_PATH];
+ DWORD pathStrSize = sizeof(pathStr);
+ DWORD type;
+
+ result = SHGetValue(key, name, TEXT("Path"), &type, (LPBYTE)pathStr, &pathStrSize);
+ if (result != ERROR_SUCCESS || type != REG_SZ)
+ continue;
+
+ paths.add(String(pathStr, pathStrSize / sizeof(WCHAR) - 1));
+ }
+
+ RegCloseKey(key);
+}
+
+void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const
+{
+ // FIXME: This should be a case insensitive set.
+ HashSet<String> uniqueFilenames;
+
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAW findFileData;
+
+ String oldWMPPluginPath;
+ String newWMPPluginPath;
+
+ Vector<String>::const_iterator end = m_pluginDirectories.end();
+ for (Vector<String>::const_iterator it = m_pluginDirectories.begin(); it != end; ++it) {
+ String pattern = *it + "\\*";
+
+ hFind = FindFirstFileW(pattern.charactersWithNullTermination(), &findFileData);
+
+ if (hFind == INVALID_HANDLE_VALUE)
+ continue;
+
+ do {
+ if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+
+ String filename = String(findFileData.cFileName, wcslen(findFileData.cFileName));
+ if ((!filename.startsWith("np", false) || !filename.endsWith("dll", false)) &&
+ (!equalIgnoringCase(filename, "Plugin.dll") || !it->endsWith("Shockwave 10", false)))
+ continue;
+
+ String fullPath = *it + "\\" + filename;
+ if (!uniqueFilenames.add(fullPath).second)
+ continue;
+
+ paths.add(fullPath);
+
+ if (equalIgnoringCase(filename, "npdsplay.dll"))
+ oldWMPPluginPath = fullPath;
+ else if (equalIgnoringCase(filename, "np-mswmp.dll"))
+ newWMPPluginPath = fullPath;
+
+ } while (FindNextFileW(hFind, &findFileData) != 0);
+
+ FindClose(hFind);
+ }
+
+ addPluginPathsFromRegistry(HKEY_LOCAL_MACHINE, paths);
+ addPluginPathsFromRegistry(HKEY_CURRENT_USER, paths);
+
+ // If both the old and new WMP plugin are present in the plugins set,
+ // we remove the old one so we don't end up choosing the old one.
+ if (!oldWMPPluginPath.isEmpty() && !newWMPPluginPath.isEmpty())
+ paths.remove(oldWMPPluginPath);
+}
+
+static inline Vector<int> parseVersionString(const String& versionString)
+{
+ Vector<int> version;
+
+ unsigned startPos = 0;
+ unsigned endPos;
+
+ while (startPos < versionString.length()) {
+ for (endPos = startPos; endPos < versionString.length(); ++endPos)
+ if (versionString[endPos] == '.' || versionString[endPos] == '_')
+ break;
+
+ int versionComponent = versionString.substring(startPos, endPos - startPos).toInt();
+ version.append(versionComponent);
+
+ startPos = endPos + 1;
+ }
+
+ return version;
+}
+
+// This returns whether versionA is higher than versionB
+static inline bool compareVersions(const Vector<int>& versionA, const Vector<int>& versionB)
+{
+ for (unsigned i = 0; i < versionA.size(); i++) {
+ if (i >= versionB.size())
+ return true;
+
+ if (versionA[i] > versionB[i])
+ return true;
+ else if (versionA[i] < versionB[i])
+ return false;
+ }
+
+ // If we come here, the versions are either the same or versionB has an extra component, just return false
+ return false;
+}
+
+static inline void addMozillaPluginDirectories(Vector<String>& directories)
+{
+ // Enumerate all Mozilla plugin directories in the registry
+ HKEY key;
+ LONG result;
+
+ result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Mozilla"), 0, KEY_READ, &key);
+ if (result == ERROR_SUCCESS) {
+ WCHAR name[128];
+ FILETIME lastModified;
+
+ // Enumerate subkeys
+ for (int i = 0;; i++) {
+ DWORD nameLen = sizeof(name) / sizeof(WCHAR);
+ result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
+
+ if (result != ERROR_SUCCESS)
+ break;
+
+ String extensionsPath = String(name, nameLen) + "\\Extensions";
+ HKEY extensionsKey;
+
+ // Try opening the key
+ result = RegOpenKeyEx(key, extensionsPath.charactersWithNullTermination(), 0, KEY_READ, &extensionsKey);
+
+ if (result == ERROR_SUCCESS) {
+ // Now get the plugins directory
+ WCHAR pluginsDirectoryStr[_MAX_PATH];
+ DWORD pluginsDirectorySize = sizeof(pluginsDirectoryStr);
+ DWORD type;
+
+ result = RegQueryValueEx(extensionsKey, TEXT("Plugins"), 0, &type, (LPBYTE)&pluginsDirectoryStr, &pluginsDirectorySize);
+
+ if (result == ERROR_SUCCESS && type == REG_SZ)
+ directories.append(String(pluginsDirectoryStr, pluginsDirectorySize / sizeof(WCHAR) - 1));
+
+ RegCloseKey(extensionsKey);
+ }
+ }
+
+ RegCloseKey(key);
+ }
+}
+
+static inline void addWindowsMediaPlayerPluginDirectory(Vector<String>& directories)
+{
+ // The new WMP Firefox plugin is installed in \PFiles\Plugins if it can't find any Firefox installs
+ WCHAR pluginDirectoryStr[_MAX_PATH + 1];
+ DWORD pluginDirectorySize = ::ExpandEnvironmentStringsW(TEXT("%SYSTEMDRIVE%\\PFiles\\Plugins"), pluginDirectoryStr, _countof(pluginDirectoryStr));
+
+ if (pluginDirectorySize > 0 && pluginDirectorySize <= _countof(pluginDirectoryStr))
+ directories.append(String(pluginDirectoryStr, pluginDirectorySize - 1));
+
+ DWORD type;
+ WCHAR installationDirectoryStr[_MAX_PATH];
+ DWORD installationDirectorySize = sizeof(installationDirectoryStr);
+
+ HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\MediaPlayer"), TEXT("Installation Directory"), &type, (LPBYTE)&installationDirectoryStr, &installationDirectorySize);
+
+ if (result == ERROR_SUCCESS && type == REG_SZ)
+ directories.append(String(installationDirectoryStr, installationDirectorySize / sizeof(WCHAR) - 1));
+}
+
+static inline void addQuickTimePluginDirectory(Vector<String>& directories)
+{
+ DWORD type;
+ WCHAR installationDirectoryStr[_MAX_PATH];
+ DWORD installationDirectorySize = sizeof(installationDirectoryStr);
+
+ HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Apple Computer, Inc.\\QuickTime"), TEXT("InstallDir"), &type, (LPBYTE)&installationDirectoryStr, &installationDirectorySize);
+
+ if (result == ERROR_SUCCESS && type == REG_SZ) {
+ String pluginDir = String(installationDirectoryStr, installationDirectorySize / sizeof(WCHAR) - 1) + "\\plugins";
+ directories.append(pluginDir);
+ }
+}
+
+static inline void addAdobeAcrobatPluginDirectory(Vector<String>& directories)
+{
+ HKEY key;
+ HRESULT result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Adobe\\Acrobat Reader"), 0, KEY_READ, &key);
+ if (result != ERROR_SUCCESS)
+ return;
+
+ WCHAR name[128];
+ FILETIME lastModified;
+
+ Vector<int> latestAcrobatVersion;
+ String latestAcrobatVersionString;
+
+ // Enumerate subkeys
+ for (int i = 0;; i++) {
+ DWORD nameLen = sizeof(name) / sizeof(WCHAR);
+ result = RegEnumKeyExW(key, i, name, &nameLen, 0, 0, 0, &lastModified);
+
+ if (result != ERROR_SUCCESS)
+ break;
+
+ Vector<int> acrobatVersion = parseVersionString(String(name, nameLen));
+ if (compareVersions(acrobatVersion, latestAcrobatVersion)) {
+ latestAcrobatVersion = acrobatVersion;
+ latestAcrobatVersionString = String(name, nameLen);
+ }
+ }
+
+ if (!latestAcrobatVersionString.isNull()) {
+ DWORD type;
+ WCHAR acrobatInstallPathStr[_MAX_PATH];
+ DWORD acrobatInstallPathSize = sizeof(acrobatInstallPathStr);
+
+ String acrobatPluginKeyPath = "Software\\Adobe\\Acrobat Reader\\" + latestAcrobatVersionString + "\\InstallPath";
+ result = SHGetValue(HKEY_LOCAL_MACHINE, acrobatPluginKeyPath.charactersWithNullTermination(), 0, &type, (LPBYTE)acrobatInstallPathStr, &acrobatInstallPathSize);
+
+ if (result == ERROR_SUCCESS) {
+ String acrobatPluginDirectory = String(acrobatInstallPathStr, acrobatInstallPathSize / sizeof(WCHAR) - 1) + "\\browser";
+ directories.append(acrobatPluginDirectory);
+ }
+ }
+
+ RegCloseKey(key);
+}
+
+static inline String safariPluginsDirectory()
+{
+ WCHAR moduleFileNameStr[_MAX_PATH];
+ static String pluginsDirectory;
+ static bool cachedPluginDirectory = false;
+
+ if (!cachedPluginDirectory) {
+ cachedPluginDirectory = true;
+
+ int moduleFileNameLen = GetModuleFileName(0, moduleFileNameStr, _MAX_PATH);
+
+ if (!moduleFileNameLen || moduleFileNameLen == _MAX_PATH)
+ goto exit;
+
+ if (!PathRemoveFileSpec(moduleFileNameStr))
+ goto exit;
+
+ pluginsDirectory = String(moduleFileNameStr) + "\\Plugins";
+ }
+exit:
+ return pluginsDirectory;
+}
+
+static inline void addMacromediaPluginDirectories(Vector<String>& directories)
+{
+ WCHAR systemDirectoryStr[MAX_PATH];
+
+ if (GetSystemDirectory(systemDirectoryStr, _countof(systemDirectoryStr)) == 0)
+ return;
+
+ WCHAR macromediaDirectoryStr[MAX_PATH];
+
+ PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Flash"));
+ directories.append(macromediaDirectoryStr);
+
+ PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Shockwave 10"));
+ directories.append(macromediaDirectoryStr);
+}
+
+Vector<String> PluginDatabase::defaultPluginDirectories()
+{
+ Vector<String> directories;
+ String ourDirectory = safariPluginsDirectory();
+
+ if (!ourDirectory.isNull())
+ directories.append(ourDirectory);
+ addQuickTimePluginDirectory(directories);
+ addAdobeAcrobatPluginDirectory(directories);
+ addMozillaPluginDirectories(directories);
+ addWindowsMediaPlayerPluginDirectory(directories);
+ addMacromediaPluginDirectories(directories);
+
+ return directories;
+}
+
+bool PluginDatabase::isPreferredPluginDirectory(const String& directory)
+{
+ String ourDirectory = safariPluginsDirectory();
+
+ if (!ourDirectory.isNull() && !directory.isNull())
+ return ourDirectory == directory;
+
+ return false;
+}
+
+}
diff --git a/WebCore/plugins/win/PluginMessageThrottlerWin.cpp b/WebCore/plugins/win/PluginMessageThrottlerWin.cpp
new file mode 100644
index 0000000..27bf5b9
--- /dev/null
+++ b/WebCore/plugins/win/PluginMessageThrottlerWin.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2006, 2007, 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 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 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 "PluginMessageThrottlerWin.h"
+
+#include "PluginView.h"
+#include <wtf/ASCIICType.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+static const double MessageThrottleTimeInterval = 0.001;
+
+PluginMessageThrottlerWin::PluginMessageThrottlerWin(PluginView* pluginView)
+ : m_back(0), m_front(0)
+ , m_pluginView(pluginView)
+ , m_messageThrottleTimer(this, &PluginMessageThrottlerWin::messageThrottleTimerFired)
+{
+ // Initialize the free list with our inline messages
+ for (unsigned i = 0; i < NumInlineMessages - 1; i++)
+ m_inlineMessages[i].next = &m_inlineMessages[i + 1];
+ m_inlineMessages[NumInlineMessages - 1].next = 0;
+ m_freeInlineMessages = &m_inlineMessages[0];
+}
+
+PluginMessageThrottlerWin::~PluginMessageThrottlerWin()
+{
+ PluginMessage* next;
+
+ for (PluginMessage* message = m_front; message; message = next) {
+ next = message->next;
+ freeMessage(message);
+ }
+}
+
+void PluginMessageThrottlerWin::appendMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PluginMessage* message = allocateMessage();
+
+ message->hWnd = hWnd;
+ message->msg = msg;
+ message->wParam = wParam;
+ message->lParam = lParam;
+ message->next = 0;
+
+ if (m_back)
+ m_back->next = message;
+ m_back = message;
+ if (!m_front)
+ m_front = message;
+
+ if (!m_messageThrottleTimer.isActive())
+ m_messageThrottleTimer.startOneShot(MessageThrottleTimeInterval);
+}
+
+void PluginMessageThrottlerWin::messageThrottleTimerFired(Timer<PluginMessageThrottlerWin>*)
+{
+ PluginMessage* message = m_front;
+ m_front = m_front->next;
+ if (message == m_back)
+ m_back = 0;
+
+ ::CallWindowProc(m_pluginView->pluginWndProc(), message->hWnd, message->msg, message->wParam, message->lParam);
+
+ freeMessage(message);
+
+ if (m_front)
+ m_messageThrottleTimer.startOneShot(MessageThrottleTimeInterval);
+}
+
+PluginMessage* PluginMessageThrottlerWin::allocateMessage()
+{
+ PluginMessage *message;
+
+ if (m_freeInlineMessages) {
+ message = m_freeInlineMessages;
+ m_freeInlineMessages = message->next;
+ } else
+ message = new PluginMessage;
+
+ return message;
+}
+
+bool PluginMessageThrottlerWin::isInlineMessage(PluginMessage* message)
+{
+ return message >= &m_inlineMessages[0] && message <= &m_inlineMessages[NumInlineMessages - 1];
+}
+
+void PluginMessageThrottlerWin::freeMessage(PluginMessage* message)
+{
+ if (isInlineMessage(message)) {
+ message->next = m_freeInlineMessages;
+ m_freeInlineMessages = message;
+ } else
+ delete message;
+}
+
+} // namespace WebCore
diff --git a/WebCore/plugins/win/PluginMessageThrottlerWin.h b/WebCore/plugins/win/PluginMessageThrottlerWin.h
new file mode 100644
index 0000000..c74beab
--- /dev/null
+++ b/WebCore/plugins/win/PluginMessageThrottlerWin.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006, 2007, 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 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 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 PluginMessageThrottlerWin_h
+#define PluginMessageThrottlerWin_h
+
+#include "Timer.h"
+
+#include <windows.h>
+
+namespace WebCore {
+ class PluginView;
+
+ struct PluginMessage {
+ HWND hWnd;
+ UINT msg;
+ WPARAM wParam;
+ LPARAM lParam;
+
+ struct PluginMessage* next;
+ };
+
+ class PluginMessageThrottlerWin {
+ public:
+ PluginMessageThrottlerWin(PluginView*);
+ ~PluginMessageThrottlerWin();
+
+ void appendMessage(HWND, UINT msg, WPARAM, LPARAM);
+
+ private:
+ void messageThrottleTimerFired(Timer<PluginMessageThrottlerWin>*);
+ PluginMessage* allocateMessage();
+ bool isInlineMessage(PluginMessage* message);
+ void freeMessage(PluginMessage* message);
+
+ PluginView* m_pluginView;
+ PluginMessage* m_back;
+ PluginMessage* m_front;
+
+ static const int NumInlineMessages = 4;
+ PluginMessage m_inlineMessages[NumInlineMessages];
+ PluginMessage* m_freeInlineMessages;
+
+ Timer<PluginMessageThrottlerWin> m_messageThrottleTimer;
+ };
+
+} // namespace WebCore
+
+#endif // PluginMessageThrottlerWin_h
diff --git a/WebCore/plugins/win/PluginPackageWin.cpp b/WebCore/plugins/win/PluginPackageWin.cpp
new file mode 100644
index 0000000..d2c26e2
--- /dev/null
+++ b/WebCore/plugins/win/PluginPackageWin.cpp
@@ -0,0 +1,374 @@
+/*
+ * 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 "CString.h"
+#include "MIMETypeRegistry.h"
+#include "PluginDatabase.h"
+#include "PluginDebug.h"
+#include "Timer.h"
+#include "npruntime_impl.h"
+#include <string.h>
+#include <wtf/OwnArrayPtr.h>
+#include <shlwapi.h>
+
+namespace WebCore {
+
+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);
+ if (!retval || bufferLength == 0)
+ return String();
+
+ // Subtract 1 from the length; we don't want the trailing null character.
+ return String(reinterpret_cast<UChar*>(buffer), bufferLength - 1);
+}
+
+int PluginPackage::compareFileVersion(const PlatformModuleVersion& compareVersion) 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;
+ return 0;
+}
+
+bool PluginPackage::isPluginBlacklisted()
+{
+ 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
+ static const PlatformModuleVersion slPluginMinRequired(0x51BE0000, 0x00010000);
+
+ if (compareFileVersion(slPluginMinRequired) < 0)
+ return true;
+ } else if (fileName() == "npmozax.dll")
+ // Bug 15217: Mozilla ActiveX control complains about missing xpcom_core.dll
+ return true;
+
+ return false;
+}
+
+void PluginPackage::determineQuirks(const String& mimeType)
+{
+ if (mimeType == "application/x-shockwave-flash") {
+ static const PlatformModuleVersion flashTenVersion(0x00000000, 0x000a0000);
+
+ // Pre 10 Flash only requests windowless plugins if we return a mozilla user agent
+ if (compareFileVersion(flashTenVersion) < 0)
+ 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);
+
+ static const PlatformModuleVersion lastKnownUnloadableRealPlayerVersion(0x000B0B24, 0x00060000);
+
+ // 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]);
+
+ if (!GetFileVersionInfoW(m_path.charactersWithNullTermination(), 0, versionInfoSize, versionInfoData.get()))
+ return false;
+
+ m_name = getVersionInfo(versionInfoData.get(), "ProductName");
+ m_description = getVersionInfo(versionInfoData.get(), "FileDescription");
+ if (m_name.isNull() || m_description.isNull())
+ return false;
+
+ VS_FIXEDFILEINFO* info;
+ UINT infoSize;
+ if (!VerQueryValue(versionInfoData.get(), TEXT("\\"), (LPVOID*) &info, &infoSize) || infoSize < sizeof(VS_FIXEDFILEINFO))
+ return false;
+ m_moduleVersion.leastSig = info->dwFileVersionLS;
+ m_moduleVersion.mostSig = info->dwFileVersionMS;
+
+ if (isPluginBlacklisted())
+ return false;
+
+ 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);
+
+ 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> extensionsVector;
+ extensionList.split(',', extensionsVector);
+
+ // Get rid of the extension list that may be at the end of the description string.
+ int pos = description.find("(*");
+ if (pos != -1) {
+ // 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);
+
+ m_mimeToExtensions.add(type, extensionsVector);
+ m_mimeToDescriptions.add(type, description);
+ }
+
+ return true;
+}
+
+bool PluginPackage::load()
+{
+ if (m_freeLibraryTimer.isActive()) {
+ ASSERT(m_module);
+ m_freeLibraryTimer.stop();
+ } else if (m_isLoaded) {
+ if (m_quirks.contains(PluginQuirkDontAllowMultipleInstances))
+ return false;
+ m_loadCount++;
+ return true;
+ } else {
+ WCHAR currentPath[MAX_PATH];
+
+ if (!::GetCurrentDirectoryW(MAX_PATH, currentPath))
+ return false;
+
+ String path = m_path.substring(0, m_path.reverseFind('\\'));
+
+ if (!::SetCurrentDirectoryW(path.charactersWithNullTermination()))
+ return false;
+
+ // Load the library
+ m_module = ::LoadLibraryW(m_path.charactersWithNullTermination());
+
+ if (!::SetCurrentDirectoryW(currentPath)) {
+ if (m_module)
+ ::FreeLibrary(m_module);
+ return false;
+ }
+ }
+
+ if (!m_module)
+ return false;
+
+ m_isLoaded = true;
+
+ NP_GetEntryPointsFuncPtr NP_GetEntryPoints = 0;
+ NP_InitializeFuncPtr NP_Initialize = 0;
+ NPError npErr;
+
+ NP_Initialize = (NP_InitializeFuncPtr)GetProcAddress(m_module, "NP_Initialize");
+ NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)GetProcAddress(m_module, "NP_GetEntryPoints");
+ m_NPP_Shutdown = (NPP_ShutdownProcPtr)GetProcAddress(m_module, "NP_Shutdown");
+
+ if (!NP_Initialize || !NP_GetEntryPoints || !m_NPP_Shutdown)
+ goto abort;
+
+ memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs));
+ m_pluginFuncs.size = sizeof(m_pluginFuncs);
+
+ npErr = NP_GetEntryPoints(&m_pluginFuncs);
+ LOG_NPERROR(npErr);
+ if (npErr != NPERR_NO_ERROR)
+ goto abort;
+
+ 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;
+ m_browserFuncs.construct = _NPN_Construct;
+
+ npErr = NP_Initialize(&m_browserFuncs);
+ LOG_NPERROR(npErr);
+
+ if (npErr != NPERR_NO_ERROR)
+ goto abort;
+
+ m_loadCount++;
+ return true;
+
+abort:
+ unloadWithoutShutdown();
+ return false;
+}
+
+unsigned PluginPackage::hash() const
+{
+ const unsigned hashCodes[] = {
+ m_name.impl()->hash(),
+ m_description.impl()->hash(),
+ m_mimeToExtensions.size()
+ };
+
+ return StringImpl::computeHash(reinterpret_cast<const UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+}
+
+bool PluginPackage::equal(const PluginPackage& a, const PluginPackage& b)
+{
+ if (a.m_name != b.m_name)
+ return false;
+
+ if (a.m_description != b.m_description)
+ return false;
+
+ if (a.m_mimeToExtensions.size() != b.m_mimeToExtensions.size())
+ return false;
+
+ MIMEToExtensionsMap::const_iterator::Keys end = a.m_mimeToExtensions.end().keys();
+ for (MIMEToExtensionsMap::const_iterator::Keys it = a.m_mimeToExtensions.begin().keys(); it != end; ++it) {
+ if (!b.m_mimeToExtensions.contains(*it))
+ return false;
+ }
+
+ return true;
+}
+
+}
diff --git a/WebCore/plugins/win/PluginViewWin.cpp b/WebCore/plugins/win/PluginViewWin.cpp
new file mode 100644
index 0000000..127d3fc
--- /dev/null
+++ b/WebCore/plugins/win/PluginViewWin.cpp
@@ -0,0 +1,861 @@
+/*
+ * Copyright (C) 2006, 2007, 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 "PluginView.h"
+
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "EventNames.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "FrameTree.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
+#include "JSDOMWindow.h"
+#include "KeyboardEvent.h"
+#include "MIMETypeRegistry.h"
+#include "MouseEvent.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "FocusController.h"
+#include "PlatformMouseEvent.h"
+#include "PluginMessageThrottlerWin.h"
+#include "PluginPackage.h"
+#include "PluginMainThreadScheduler.h"
+#include "JSDOMBinding.h"
+#include "ScriptController.h"
+#include "PluginDatabase.h"
+#include "PluginDebug.h"
+#include "PluginPackage.h"
+#include "c_instance.h"
+#include "npruntime_impl.h"
+#include "runtime_root.h"
+#include "Settings.h"
+#include "runtime.h"
+#include <runtime/JSLock.h>
+#include <runtime/JSValue.h>
+#include <wtf/ASCIICType.h>
+
+#if PLATFORM(QT)
+#include <QWidget.h>
+#endif
+
+static inline HWND windowHandleForPlatformWidget(PlatformWidget widget)
+{
+#if PLATFORM(QT)
+ if (!widget)
+ return 0;
+ return widget->winId();
+#else
+ return widget;
+#endif
+}
+
+using JSC::ExecState;
+using JSC::JSLock;
+using JSC::JSObject;
+using JSC::UString;
+
+using std::min;
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+const LPCWSTR kWebPluginViewdowClassName = L"WebPluginView";
+const LPCWSTR kWebPluginViewProperty = L"WebPluginViewProperty";
+
+static const char* MozillaUserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
+
+static bool registerPluginView()
+{
+ static bool haveRegisteredWindowClass = false;
+ if (haveRegisteredWindowClass)
+ return true;
+
+ haveRegisteredWindowClass = true;
+
+#if PLATFORM(QT)
+ Page::setInstanceHandle((HINSTANCE)(qWinAppInst()));
+#endif
+
+ ASSERT(Page::instanceHandle());
+
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_DBLCLKS;
+ wcex.lpfnWndProc = DefWindowProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = Page::instanceHandle();
+ wcex.hIcon = 0;
+ wcex.hCursor = LoadCursor(0, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)COLOR_WINDOW;
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = kWebPluginViewdowClassName;
+ wcex.hIconSm = 0;
+
+ return !!RegisterClassEx(&wcex);
+}
+
+LRESULT CALLBACK PluginView::PluginViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
+
+ return pluginView->wndProc(hWnd, message, wParam, lParam);
+}
+
+static bool isWindowsMessageUserGesture(UINT message)
+{
+ switch (message) {
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_KEYUP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+LRESULT
+PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // <rdar://5711136> Sometimes Flash will call SetCapture before creating
+ // a full-screen window and will not release it, which causes the
+ // full-screen window to never receive mouse events. We set/release capture
+ // on mouse down/up before sending the event to the plug-in to prevent that.
+ switch (message) {
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ ::SetCapture(hWnd);
+ break;
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ ::ReleaseCapture();
+ break;
+ }
+
+ if (message == m_lastMessage &&
+ m_plugin->quirks().contains(PluginQuirkDontCallWndProcForSameMessageRecursively) &&
+ m_isCallingPluginWndProc)
+ return 1;
+
+ if (message == WM_USER + 1 &&
+ m_plugin->quirks().contains(PluginQuirkThrottleWMUserPlusOneMessages)) {
+ if (!m_messageThrottler)
+ m_messageThrottler.set(new PluginMessageThrottlerWin(this));
+
+ m_messageThrottler->appendMessage(hWnd, message, wParam, lParam);
+ return 0;
+ }
+
+ m_lastMessage = message;
+ m_isCallingPluginWndProc = true;
+
+ // If the plug-in doesn't explicitly support changing the pop-up state, we enable
+ // popups for all user gestures.
+ // Note that we need to pop the state in a timer, because the Flash plug-in
+ // pops up windows in response to a posted message.
+ if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE &&
+ isWindowsMessageUserGesture(message) && !m_popPopupsStateTimer.isActive()) {
+
+ pushPopupsEnabledState(true);
+
+ m_popPopupsStateTimer.startOneShot(0);
+ }
+
+ // Call the plug-in's window proc.
+ LRESULT result = ::CallWindowProc(m_pluginWndProc, hWnd, message, wParam, lParam);
+
+ m_isCallingPluginWndProc = false;
+
+ return result;
+}
+
+void PluginView::updatePluginWidget() const
+{
+ if (!parent())
+ return;
+
+ ASSERT(parent()->isFrameView());
+ FrameView* frameView = static_cast<FrameView*>(parent());
+
+ IntRect oldWindowRect = m_windowRect;
+ IntRect oldClipRect = m_clipRect;
+
+ m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
+ m_clipRect = windowClipRect();
+ m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
+
+ if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) {
+ HRGN rgn;
+
+ setCallingPlugin(true);
+
+ // 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);
+
+ if (clipToZeroRect) {
+ rgn = ::CreateRectRgn(0, 0, 0, 0);
+ ::SetWindowRgn(platformPluginWidget(), rgn, FALSE);
+ } else {
+ rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom());
+ ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
+ }
+
+ if (m_windowRect != oldWindowRect)
+ ::MoveWindow(platformPluginWidget(), m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), TRUE);
+
+ if (clipToZeroRect) {
+ rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom());
+ ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
+ }
+
+ setCallingPlugin(false);
+ }
+}
+
+void PluginView::setFocus()
+{
+ if (platformPluginWidget())
+ SetFocus(platformPluginWidget());
+
+ Widget::setFocus();
+}
+
+void PluginView::show()
+{
+ setSelfVisible(true);
+
+ if (isParentVisible() && platformPluginWidget())
+ ShowWindow(platformPluginWidget(), SW_SHOWNA);
+
+ Widget::show();
+}
+
+void PluginView::hide()
+{
+ setSelfVisible(false);
+
+ if (isParentVisible() && platformPluginWidget())
+ ShowWindow(platformPluginWidget(), SW_HIDE);
+
+ Widget::hide();
+}
+
+void PluginView::paintMissingPluginIcon(GraphicsContext* context, const IntRect& rect)
+{
+ static RefPtr<Image> nullPluginImage;
+ if (!nullPluginImage)
+ nullPluginImage = Image::loadPlatformResource("nullPlugin");
+
+ IntRect imageRect(frameRect().x(), frameRect().y(), nullPluginImage->width(), nullPluginImage->height());
+
+ int xOffset = (frameRect().width() - imageRect.width()) / 2;
+ int yOffset = (frameRect().height() - imageRect.height()) / 2;
+
+ imageRect.move(xOffset, yOffset);
+
+ if (!rect.intersects(imageRect))
+ return;
+
+ context->save();
+ context->clip(windowClipRect());
+ context->drawImage(nullPluginImage.get(), imageRect.location());
+ context->restore();
+}
+
+bool PluginView::dispatchNPEvent(NPEvent& npEvent)
+{
+ if (!m_plugin->pluginFuncs()->event)
+ return true;
+
+ bool shouldPop = false;
+
+ if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE && isWindowsMessageUserGesture(npEvent.event)) {
+ pushPopupsEnabledState(true);
+ shouldPop = true;
+ }
+
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ setCallingPlugin(true);
+ bool result = m_plugin->pluginFuncs()->event(m_instance, &npEvent);
+ setCallingPlugin(false);
+
+ if (shouldPop)
+ popPopupsEnabledState();
+
+ return result;
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_isStarted) {
+ // Draw the "missing plugin" image
+ paintMissingPluginIcon(context, rect);
+ return;
+ }
+
+ if (m_isWindowed || context->paintingDisabled())
+ return;
+
+ ASSERT(parent()->isFrameView());
+ IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
+ HDC hdc = context->getWindowsContext(rectInWindow, m_isTransparent);
+ NPEvent npEvent;
+
+ // On Safari/Windows without transparency layers the GraphicsContext returns the HDC
+ // of the window and the plugin expects that the passed in DC has window coordinates.
+ // In the Qt port we always draw in an offscreen buffer and therefore need to preserve
+ // the translation set in getWindowsContext.
+#if !PLATFORM(QT)
+ if (!context->inTransparencyLayer()) {
+ XFORM transform;
+ GetWorldTransform(hdc, &transform);
+ transform.eDx = 0;
+ transform.eDy = 0;
+ SetWorldTransform(hdc, &transform);
+ }
+#endif
+
+ m_npWindow.type = NPWindowTypeDrawable;
+ m_npWindow.window = hdc;
+
+ IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location());
+
+ WINDOWPOS windowpos;
+ memset(&windowpos, 0, sizeof(windowpos));
+
+ windowpos.x = p.x();
+ windowpos.y = p.y();
+ windowpos.cx = frameRect().width();
+ windowpos.cy = frameRect().height();
+
+ npEvent.event = WM_WINDOWPOSCHANGED;
+ npEvent.lParam = reinterpret_cast<uint32>(&windowpos);
+ npEvent.wParam = 0;
+
+ dispatchNPEvent(npEvent);
+
+ setNPWindowRect(frameRect());
+
+ npEvent.event = WM_PAINT;
+ npEvent.wParam = reinterpret_cast<uint32>(hdc);
+
+ // This is supposed to be a pointer to the dirty rect, but it seems that the Flash plugin
+ // ignores it so we just pass null.
+ npEvent.lParam = 0;
+
+ dispatchNPEvent(npEvent);
+
+ context->releaseWindowsContext(hdc, frameRect(), m_isTransparent);
+}
+
+void PluginView::handleKeyboardEvent(KeyboardEvent* event)
+{
+ NPEvent npEvent;
+
+ npEvent.wParam = event->keyCode();
+
+ if (event->type() == eventNames().keydownEvent) {
+ npEvent.event = WM_KEYDOWN;
+ npEvent.lParam = 0;
+ } else if (event->type() == eventNames().keyupEvent) {
+ npEvent.event = WM_KEYUP;
+ npEvent.lParam = 0x8000;
+ }
+
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ if (!dispatchNPEvent(npEvent))
+ event->setDefaultHandled();
+}
+
+extern HCURSOR lastSetCursor;
+extern bool ignoreNextSetCursor;
+
+void PluginView::handleMouseEvent(MouseEvent* event)
+{
+ NPEvent npEvent;
+
+ IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(IntPoint(event->pageX(), event->pageY()));
+
+ npEvent.lParam = MAKELPARAM(p.x(), p.y());
+ npEvent.wParam = 0;
+
+ if (event->ctrlKey())
+ npEvent.wParam |= MK_CONTROL;
+ if (event->shiftKey())
+ npEvent.wParam |= MK_SHIFT;
+
+ if (event->type() == eventNames().mousemoveEvent ||
+ event->type() == eventNames().mouseoutEvent ||
+ event->type() == eventNames().mouseoverEvent) {
+ npEvent.event = WM_MOUSEMOVE;
+ if (event->buttonDown())
+ switch (event->button()) {
+ case LeftButton:
+ npEvent.wParam |= MK_LBUTTON;
+ break;
+ case MiddleButton:
+ npEvent.wParam |= MK_MBUTTON;
+ break;
+ case RightButton:
+ npEvent.wParam |= MK_RBUTTON;
+ break;
+ }
+ }
+ else if (event->type() == eventNames().mousedownEvent) {
+ // Focus the plugin
+ if (Page* page = m_parentFrame->page())
+ page->focusController()->setFocusedFrame(m_parentFrame);
+ m_parentFrame->document()->setFocusedNode(m_element);
+ switch (event->button()) {
+ case 0:
+ npEvent.event = WM_LBUTTONDOWN;
+ break;
+ case 1:
+ npEvent.event = WM_MBUTTONDOWN;
+ break;
+ case 2:
+ npEvent.event = WM_RBUTTONDOWN;
+ break;
+ }
+ } else if (event->type() == eventNames().mouseupEvent) {
+ switch (event->button()) {
+ case 0:
+ npEvent.event = WM_LBUTTONUP;
+ break;
+ case 1:
+ npEvent.event = WM_MBUTTONUP;
+ break;
+ case 2:
+ npEvent.event = WM_RBUTTONUP;
+ break;
+ }
+ } else
+ return;
+
+ HCURSOR currentCursor = ::GetCursor();
+
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ if (!dispatchNPEvent(npEvent))
+ event->setDefaultHandled();
+
+#if !PLATFORM(QT)
+ // Currently, Widget::setCursor is always called after this function in EventHandler.cpp
+ // and since we don't want that we set ignoreNextSetCursor to true here to prevent that.
+ ignoreNextSetCursor = true;
+ lastSetCursor = ::GetCursor();
+#endif
+}
+
+void PluginView::setParent(ScrollView* parent)
+{
+ Widget::setParent(parent);
+
+ if (parent)
+ init();
+ else {
+ if (!platformPluginWidget())
+ return;
+
+ // If the plug-in window or one of its children have the focus, we need to
+ // clear it to prevent the web view window from being focused because that can
+ // trigger a layout while the plugin element is being detached.
+ HWND focusedWindow = ::GetFocus();
+ if (platformPluginWidget() == focusedWindow || ::IsChild(platformPluginWidget(), focusedWindow))
+ ::SetFocus(0);
+ }
+
+}
+
+void PluginView::setParentVisible(bool visible)
+{
+ if (isParentVisible() == visible)
+ return;
+
+ Widget::setParentVisible(visible);
+
+ if (isSelfVisible() && platformPluginWidget()) {
+ if (visible)
+ ShowWindow(platformPluginWidget(), SW_SHOWNA);
+ else
+ ShowWindow(platformPluginWidget(), SW_HIDE);
+ }
+}
+
+void PluginView::setNPWindowRect(const IntRect& rect)
+{
+ if (!m_isStarted)
+ return;
+
+ IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(rect.location());
+ m_npWindow.x = p.x();
+ m_npWindow.y = p.y();
+
+ m_npWindow.width = rect.width();
+ m_npWindow.height = rect.height();
+
+ m_npWindow.clipRect.left = 0;
+ m_npWindow.clipRect.top = 0;
+ m_npWindow.clipRect.right = rect.width();
+ m_npWindow.clipRect.bottom = rect.height();
+
+ if (m_plugin->pluginFuncs()->setwindow) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+
+ if (!m_isWindowed)
+ return;
+
+ ASSERT(platformPluginWidget());
+
+ WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
+ if (currentWndProc != PluginViewWndProc)
+ m_pluginWndProc = (WNDPROC)SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG)PluginViewWndProc);
+ }
+}
+
+void PluginView::stop()
+{
+ if (!m_isStarted)
+ return;
+
+ HashSet<RefPtr<PluginStream> > streams = m_streams;
+ HashSet<RefPtr<PluginStream> >::iterator end = streams.end();
+ for (HashSet<RefPtr<PluginStream> >::iterator it = streams.begin(); it != end; ++it) {
+ (*it)->stop();
+ disconnectStream((*it).get());
+ }
+
+ ASSERT(m_streams.isEmpty());
+
+ m_isStarted = false;
+
+ // Unsubclass the window
+ if (m_isWindowed) {
+ WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
+
+ if (currentWndProc == PluginViewWndProc)
+ SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG)m_pluginWndProc);
+ }
+
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+
+ // Clear the window
+ m_npWindow.window = 0;
+ if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) {
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+ }
+
+ PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
+
+ // Destroy the plugin
+ NPSavedData* savedData = 0;
+ setCallingPlugin(true);
+ NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
+ setCallingPlugin(false);
+ LOG_NPERROR(npErr);
+
+ if (savedData) {
+ if (savedData->buf)
+ NPN_MemFree(savedData->buf);
+ NPN_MemFree(savedData);
+ }
+
+ m_instance->pdata = 0;
+}
+
+const char* PluginView::userAgentStatic()
+{
+ return 0;
+}
+
+const char* PluginView::userAgent()
+{
+ if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent))
+ return MozillaUserAgent;
+
+ if (m_userAgent.isNull())
+ m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8();
+ return m_userAgent.data();
+}
+
+NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf)
+{
+ String filename(buf, len);
+
+ if (filename.startsWith("file:///"))
+ filename = filename.substring(8);
+
+ // Get file info
+ WIN32_FILE_ATTRIBUTE_DATA attrs;
+ if (GetFileAttributesExW(filename.charactersWithNullTermination(), GetFileExInfoStandard, &attrs) == 0)
+ return NPERR_FILE_NOT_FOUND;
+
+ if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ return NPERR_FILE_NOT_FOUND;
+
+ HANDLE fileHandle = CreateFileW(filename.charactersWithNullTermination(), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+
+ if (fileHandle == INVALID_HANDLE_VALUE)
+ return NPERR_FILE_NOT_FOUND;
+
+ buffer.resize(attrs.nFileSizeLow);
+
+ DWORD bytesRead;
+ int retval = ReadFile(fileHandle, buffer.data(), attrs.nFileSizeLow, &bytesRead, 0);
+
+ CloseHandle(fileHandle);
+
+ if (retval == 0 || bytesRead != attrs.nFileSizeLow)
+ return NPERR_FILE_NOT_FOUND;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginView::getValueStatic(NPNVariable variable, void* value)
+{
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError PluginView::getValue(NPNVariable variable, void* value)
+{
+ switch (variable) {
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ case NPNVWindowNPObject: {
+ if (m_isJavaScriptPaused)
+ return NPERR_GENERIC_ERROR;
+
+ NPObject* windowScriptObject = m_parentFrame->script()->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: {
+ if (m_isJavaScriptPaused)
+ return NPERR_GENERIC_ERROR;
+
+ NPObject* pluginScriptObject = 0;
+
+ if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag))
+ pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->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;
+ }
+#endif
+
+ case NPNVnetscapeWindow: {
+ HWND* w = reinterpret_cast<HWND*>(value);
+
+ *w = windowHandleForPlatformWidget(parent() ? parent()->hostWindow()->platformWindow() : 0);
+
+ return NPERR_NO_ERROR;
+ }
+
+ case NPNVSupportsWindowless: {
+ NPBool *result = reinterpret_cast<NPBool*>(value);
+
+ *result = TRUE;
+
+ return NPERR_NO_ERROR;
+ }
+
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+void PluginView::invalidateRect(const IntRect& rect)
+{
+ if (m_isWindowed) {
+ RECT invalidRect = { rect.x(), rect.y(), rect.right(), rect.bottom() };
+ ::InvalidateRect(platformPluginWidget(), &invalidRect, false);
+ return;
+ }
+
+ invalidateWindowlessPluginRect(rect);
+}
+
+void PluginView::invalidateRect(NPRect* rect)
+{
+ if (!rect) {
+ invalidate();
+ return;
+ }
+
+ IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
+
+ if (m_isWindowed) {
+ RECT invalidRect = { r.x(), r.y(), r.right(), r.bottom() };
+ InvalidateRect(platformPluginWidget(), &invalidRect, FALSE);
+ } else {
+ if (m_plugin->quirks().contains(PluginQuirkThrottleInvalidate)) {
+ m_invalidRects.append(r);
+ if (!m_invalidateTimer.isActive())
+ m_invalidateTimer.startOneShot(0.001);
+ } else
+ invalidateRect(r);
+ }
+}
+
+void PluginView::invalidateRegion(NPRegion region)
+{
+ if (m_isWindowed)
+ return;
+
+ RECT r;
+
+ if (GetRgnBox(region, &r) == 0) {
+ invalidate();
+ return;
+ }
+
+ IntRect rect(IntPoint(r.left, r.top), IntSize(r.right-r.left, r.bottom-r.top));
+ invalidateRect(rect);
+}
+
+void PluginView::forceRedraw()
+{
+ if (m_isWindowed)
+ ::UpdateWindow(platformPluginWidget());
+ else
+ ::UpdateWindow(windowHandleForPlatformWidget(parent() ? parent()->hostWindow()->platformWindow() : 0));
+}
+
+PluginView::~PluginView()
+{
+ stop();
+
+ deleteAllValues(m_requests);
+
+ freeStringArray(m_paramNames, m_paramCount);
+ freeStringArray(m_paramValues, m_paramCount);
+
+ if (platformPluginWidget())
+ DestroyWindow(platformPluginWidget());
+
+ m_parentFrame->script()->cleanupScriptObjectsForPlugin(this);
+
+ if (m_plugin && !m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin))
+ m_plugin->unload();
+}
+
+void PluginView::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;
+ }
+
+ if (m_isWindowed) {
+ registerPluginView();
+
+ DWORD flags = WS_CHILD;
+ if (isSelfVisible())
+ flags |= WS_VISIBLE;
+
+ HWND parentWindowHandle = windowHandleForPlatformWidget(m_parentFrame->view()->hostWindow()->platformWindow());
+ HWND window = ::CreateWindowEx(0, kWebPluginViewdowClassName, 0, flags,
+ 0, 0, 0, 0, parentWindowHandle, 0, Page::instanceHandle(), 0);
+#if PLATFORM(WIN_OS) && PLATFORM(QT)
+ m_window = window;
+#else
+ setPlatformWidget(window);
+#endif
+
+ // Calling SetWindowLongPtrA here makes the window proc ASCII, which is required by at least
+ // the Shockwave Director plug-in.
+#if PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC)
+ ::SetWindowLongPtrA(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
+#else
+ ::SetWindowLongPtrA(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProcA);
+#endif
+ SetProp(platformPluginWidget(), kWebPluginViewProperty, this);
+
+ m_npWindow.type = NPWindowTypeWindow;
+ m_npWindow.window = platformPluginWidget();
+ } else {
+ m_npWindow.type = NPWindowTypeDrawable;
+ m_npWindow.window = 0;
+ }
+
+ if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))
+ setNPWindowRect(frameRect());
+
+ m_status = PluginStatusLoadedSuccessfully;
+}
+
+} // namespace WebCore