summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/plugins/win
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/plugins/win
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/plugins/win')
-rw-r--r--Source/WebCore/plugins/win/PaintHooks.asm50
-rw-r--r--Source/WebCore/plugins/win/PluginDatabaseWin.cpp451
-rw-r--r--Source/WebCore/plugins/win/PluginMessageThrottlerWin.cpp151
-rw-r--r--Source/WebCore/plugins/win/PluginMessageThrottlerWin.h74
-rw-r--r--Source/WebCore/plugins/win/PluginPackageWin.cpp342
-rw-r--r--Source/WebCore/plugins/win/PluginViewWin.cpp1080
6 files changed, 2148 insertions, 0 deletions
diff --git a/Source/WebCore/plugins/win/PaintHooks.asm b/Source/WebCore/plugins/win/PaintHooks.asm
new file mode 100644
index 0000000..1508813
--- /dev/null
+++ b/Source/WebCore/plugins/win/PaintHooks.asm
@@ -0,0 +1,50 @@
+;/*
+; Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+;
+; 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.
+;*/
+
+;HDC __stdcall _HBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
+
+PUBLIC _HBeginPaint
+
+_TEXT SEGMENT
+
+_HBeginPaint PROC
+ mov r10,rcx
+ mov eax,1017h
+ syscall
+ ret
+_HBeginPaint ENDP
+
+_TEXT ENDS
+
+;BOOL __stdcall _HEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint);
+
+PUBLIC _HEndPaint
+
+_TEXT SEGMENT
+
+_HEndPaint PROC
+ mov r10,rcx
+ mov eax,1019h
+ syscall
+ ret
+_HEndPaint ENDP
+
+_TEXT ENDS
+
+END
diff --git a/Source/WebCore/plugins/win/PluginDatabaseWin.cpp b/Source/WebCore/plugins/win/PluginDatabaseWin.cpp
new file mode 100644
index 0000000..27121c6
--- /dev/null
+++ b/Source/WebCore/plugins/win/PluginDatabaseWin.cpp
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
+ * Copyright (C) 2008-2009 Torch Mobile, 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 "PluginDatabase.h"
+
+#include "Frame.h"
+#include "KURL.h"
+#include "PluginPackage.h"
+#include <windows.h>
+#include <shlwapi.h>
+
+#if OS(WINCE)
+// WINCE doesn't support Registry Key Access Rights. The parameter should always be 0
+#ifndef KEY_ENUMERATE_SUB_KEYS
+#define KEY_ENUMERATE_SUB_KEYS 0
+#endif
+
+DWORD SHGetValue(HKEY hkey, LPCWSTR pszSubKey, LPCWSTR pszValue, LPDWORD pdwType, LPVOID pvData, LPDWORD pcbData)
+{
+ HKEY key;
+ if (RegOpenKeyEx(hkey, pszSubKey, 0, 0, &key) == ERROR_SUCCESS) {
+ DWORD result = RegQueryValueEx(key, pszValue, 0, pdwType, (LPBYTE)pvData, pcbData);
+ RegCloseKey(key);
+ return result;
+ }
+ return ERROR_INVALID_NAME;
+}
+
+BOOL PathRemoveFileSpec(LPWSTR moduleFileNameStr)
+{
+ if (!*moduleFileNameStr)
+ return FALSE;
+
+ LPWSTR lastPos = 0;
+ LPWSTR curPos = moduleFileNameStr;
+ do {
+ if (*curPos == L'/' || *curPos == L'\\')
+ lastPos = curPos;
+ } while (*++curPos);
+
+ if (lastPos == curPos - 1)
+ return FALSE;
+
+ if (lastPos)
+ *lastPos = 0;
+ else {
+ moduleFileNameStr[0] = L'\\';
+ moduleFileNameStr[1] = 0;
+ }
+
+ return TRUE;
+}
+#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 = WTF_ARRAY_LENGTH(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)
+{
+#if !OS(WINCE)
+ // 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, WTF_ARRAY_LENGTH(pluginDirectoryStr));
+
+ if (pluginDirectorySize > 0 && pluginDirectorySize <= WTF_ARRAY_LENGTH(pluginDirectoryStr))
+ directories.append(String(pluginDirectoryStr, pluginDirectorySize - 1));
+#endif
+
+ 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 void addJavaPluginDirectory(Vector<String>& directories)
+{
+ HKEY key;
+ HRESULT result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\JavaSoft\\Java Plug-in"), 0, KEY_READ, &key);
+ if (result != ERROR_SUCCESS)
+ return;
+
+ WCHAR name[128];
+ FILETIME lastModified;
+
+ Vector<int> latestJavaVersion;
+ String latestJavaVersionString;
+
+ // 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> javaVersion = parseVersionString(String(name, nameLen));
+ if (compareVersions(javaVersion, latestJavaVersion)) {
+ latestJavaVersion = javaVersion;
+ latestJavaVersionString = String(name, nameLen);
+ }
+ }
+
+ if (!latestJavaVersionString.isEmpty()) {
+ DWORD type;
+ WCHAR javaInstallPathStr[_MAX_PATH];
+ DWORD javaInstallPathSize = sizeof(javaInstallPathStr);
+ DWORD useNewPluginValue;
+ DWORD useNewPluginSize;
+
+ String javaPluginKeyPath = "Software\\JavaSoft\\Java Plug-in\\" + latestJavaVersionString;
+ result = SHGetValue(HKEY_LOCAL_MACHINE, javaPluginKeyPath.charactersWithNullTermination(), TEXT("UseNewJavaPlugin"), &type, (LPVOID)&useNewPluginValue, &useNewPluginSize);
+
+ if (result == ERROR_SUCCESS && useNewPluginValue == 1) {
+ result = SHGetValue(HKEY_LOCAL_MACHINE, javaPluginKeyPath.charactersWithNullTermination(), TEXT("JavaHome"), &type, (LPBYTE)javaInstallPathStr, &javaInstallPathSize);
+ if (result == ERROR_SUCCESS) {
+ String javaPluginDirectory = String(javaInstallPathStr, javaInstallPathSize / sizeof(WCHAR) - 1) + "\\bin\\new_plugin";
+ directories.append(javaPluginDirectory);
+ }
+ }
+ }
+
+ 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)
+{
+#if !OS(WINCE)
+ WCHAR systemDirectoryStr[MAX_PATH];
+
+ if (!GetSystemDirectory(systemDirectoryStr, WTF_ARRAY_LENGTH(systemDirectoryStr)))
+ return;
+
+ WCHAR macromediaDirectoryStr[MAX_PATH];
+
+ PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Flash"));
+ directories.append(macromediaDirectoryStr);
+
+ PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Shockwave 10"));
+ directories.append(macromediaDirectoryStr);
+#endif
+}
+
+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);
+#if PLATFORM(QT)
+ addJavaPluginDirectory(directories);
+#endif
+
+ return directories;
+}
+
+bool PluginDatabase::isPreferredPluginDirectory(const String& directory)
+{
+ String ourDirectory = safariPluginsDirectory();
+
+ if (!ourDirectory.isNull() && !directory.isNull())
+ return ourDirectory == directory;
+
+ return false;
+}
+
+}
diff --git a/Source/WebCore/plugins/win/PluginMessageThrottlerWin.cpp b/Source/WebCore/plugins/win/PluginMessageThrottlerWin.cpp
new file mode 100644
index 0000000..c5f3081
--- /dev/null
+++ b/Source/WebCore/plugins/win/PluginMessageThrottlerWin.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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>
+#include <wtf/CurrentTime.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+// Set a timer to make sure we process any queued messages at least every 16ms.
+// This value allows Flash 60 messages/second, which should be enough for video
+// playback, and also gets us over the limit for kicking into high-resolution
+// timer mode (see SharedTimerWin.cpp).
+static const double MessageThrottleTimeInterval = 0.016;
+
+// During a continuous stream of messages, process one every 5ms.
+static const double MessageDirectProcessingInterval = 0.005;
+
+PluginMessageThrottlerWin::PluginMessageThrottlerWin(PluginView* pluginView)
+ : m_pluginView(pluginView)
+ , m_back(0)
+ , m_front(0)
+ , m_messageThrottleTimer(this, &PluginMessageThrottlerWin::messageThrottleTimerFired)
+ , m_lastMessageTime(0)
+{
+ // 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 it has been more than MessageDirectProcessingInterval between throttled messages,
+ // go ahead and process a message directly.
+ double currentTime = WTF::currentTime();
+ if (currentTime - m_lastMessageTime > MessageDirectProcessingInterval) {
+ processQueuedMessage();
+ m_lastMessageTime = currentTime;
+ if (!m_front)
+ return;
+ }
+
+ if (!m_messageThrottleTimer.isActive())
+ m_messageThrottleTimer.startOneShot(MessageThrottleTimeInterval);
+}
+
+void PluginMessageThrottlerWin::processQueuedMessage()
+{
+ PluginMessage* message = m_front;
+ m_front = m_front->next;
+ if (message == m_back)
+ m_back = 0;
+
+ // Protect the PluginView from destruction while calling its window proc.
+ // <rdar://problem/6930280>
+ RefPtr<PluginView> protect(m_pluginView);
+ ::CallWindowProc(m_pluginView->pluginWndProc(), message->hWnd, message->msg, message->wParam, message->lParam);
+
+ freeMessage(message);
+}
+
+void PluginMessageThrottlerWin::messageThrottleTimerFired(Timer<PluginMessageThrottlerWin>*)
+{
+ processQueuedMessage();
+
+ 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/Source/WebCore/plugins/win/PluginMessageThrottlerWin.h b/Source/WebCore/plugins/win/PluginMessageThrottlerWin.h
new file mode 100644
index 0000000..0a7be70
--- /dev/null
+++ b/Source/WebCore/plugins/win/PluginMessageThrottlerWin.h
@@ -0,0 +1,74 @@
+/*
+ * 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 processQueuedMessage();
+ 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;
+ double m_lastMessageTime;
+ };
+
+} // namespace WebCore
+
+#endif // PluginMessageThrottlerWin_h
diff --git a/Source/WebCore/plugins/win/PluginPackageWin.cpp b/Source/WebCore/plugins/win/PluginPackageWin.cpp
new file mode 100644
index 0000000..74bd2a9
--- /dev/null
+++ b/Source/WebCore/plugins/win/PluginPackageWin.cpp
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, 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 "PluginPackage.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 <wtf/text/CString.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);
+}
+
+bool PluginPackage::isPluginBlacklisted()
+{
+ if (name() == "Citrix ICA Client") {
+ // The Citrix ICA Client plug-in requires a Mozilla-based browser; see <rdar://6418681>.
+ return true;
+ }
+
+ 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;
+ } else if (name() == "Yahoo Application State Plugin") {
+ // https://bugs.webkit.org/show_bug.cgi?id=26860
+ // Bug in Yahoo Application State plug-in earlier than 1.0.0.6 leads to heap corruption.
+ static const PlatformModuleVersion yahooAppStatePluginMinRequired(0x00000006, 0x00010000);
+ if (compareFileVersion(yahooAppStatePluginMinRequired) < 0)
+ 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" || name() == "VLC Multimedia Plug-in") {
+ // 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(const_cast<UChar*>(m_path.charactersWithNullTermination()), &zeroHandle);
+ if (versionInfoSize == 0)
+ return false;
+
+ OwnArrayPtr<char> versionInfoData(new char[versionInfoSize]);
+
+ if (!GetFileVersionInfoW(const_cast<UChar*>(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 (!VerQueryValueW(versionInfoData.get(), L"\\", (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 {
+#if OS(WINCE)
+ m_module = ::LoadLibraryW(m_path.charactersWithNullTermination());
+#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 = ::LoadLibraryExW(m_path.charactersWithNullTermination(), 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+
+ if (!::SetCurrentDirectoryW(currentPath)) {
+ if (m_module)
+ ::FreeLibrary(m_module);
+ return false;
+ }
+#endif
+ }
+
+ if (!m_module)
+ return false;
+
+ m_isLoaded = true;
+
+ NP_GetEntryPointsFuncPtr NP_GetEntryPoints = 0;
+ NP_InitializeFuncPtr NP_Initialize = 0;
+ NPError npErr;
+
+#if OS(WINCE)
+ NP_Initialize = (NP_InitializeFuncPtr)GetProcAddress(m_module, L"NP_Initialize");
+ NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)GetProcAddress(m_module, L"NP_GetEntryPoints");
+ m_NPP_Shutdown = (NPP_ShutdownProcPtr)GetProcAddress(m_module, L"NP_Shutdown");
+#else
+ 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");
+#endif
+
+ 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;
+
+ initializeBrowserFuncs();
+
+ 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 WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+}
+
+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;
+}
+
+uint16_t PluginPackage::NPVersion() const
+{
+ return NP_VERSION_MINOR;
+}
+}
diff --git a/Source/WebCore/plugins/win/PluginViewWin.cpp b/Source/WebCore/plugins/win/PluginViewWin.cpp
new file mode 100644
index 0000000..758d90a
--- /dev/null
+++ b/Source/WebCore/plugins/win/PluginViewWin.cpp
@@ -0,0 +1,1080 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2008-2009 Torch Mobile, 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 "PluginView.h"
+
+#include "BitmapImage.h"
+#include "Bridge.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoadRequest.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
+#include "HostWindow.h"
+#include "Image.h"
+#include "JSDOMBinding.h"
+#include "JSDOMWindow.h"
+#include "KeyboardEvent.h"
+#include "LocalWindowsContext.h"
+#include "MIMETypeRegistry.h"
+#include "MouseEvent.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PluginDatabase.h"
+#include "PluginDebug.h"
+#include "PluginMainThreadScheduler.h"
+#include "PluginMessageThrottlerWin.h"
+#include "PluginPackage.h"
+#include "RenderWidget.h"
+#include "ScriptController.h"
+#include "Settings.h"
+#include "WebCoreInstanceHandle.h"
+#include "c_instance.h"
+#include "npruntime_impl.h"
+#include "runtime_root.h"
+#include <runtime/JSLock.h>
+#include <runtime/JSValue.h>
+#include <wtf/ASCIICType.h>
+
+#if !PLATFORM(WX)
+#include "BitmapInfo.h"
+#endif
+
+#if OS(WINCE)
+#undef LOG_NPERROR
+#define LOG_NPERROR(x)
+#undef LOG_PLUGIN_NET_ERROR
+#define LOG_PLUGIN_NET_ERROR()
+#endif
+
+#if PLATFORM(CAIRO)
+#include <cairo-win32.h>
+#endif
+
+#if PLATFORM(QT)
+#include "QWebPageClient.h"
+#include <QWidget>
+#endif
+
+#if PLATFORM(WX)
+#include <wx/defs.h>
+#include <wx/window.h>
+#endif
+
+static inline HWND windowHandleForPageClient(PlatformPageClient client)
+{
+#if PLATFORM(QT)
+ if (!client)
+ return 0;
+ if (QWidget* pluginParent = qobject_cast<QWidget*>(client->pluginParent()))
+ return pluginParent->winId();
+ return 0;
+#elif PLATFORM(WX)
+ if (!client)
+ return 0;
+ return (HWND)client->GetHandle();
+#else
+ return client;
+#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";
+
+#if !OS(WINCE)
+// The code used to hook BeginPaint/EndPaint originally came from
+// <http://www.fengyuan.com/article/wmprint.html>.
+// Copyright (C) 2000 by Feng Yuan (www.fengyuan.com).
+
+static unsigned beginPaintSysCall;
+static BYTE* beginPaint;
+
+static unsigned endPaintSysCall;
+static BYTE* endPaint;
+
+typedef HDC (WINAPI *PtrBeginPaint)(HWND, PAINTSTRUCT*);
+typedef BOOL (WINAPI *PtrEndPaint)(HWND, const PAINTSTRUCT*);
+
+#if OS(WINDOWS) && CPU(X86_64) && COMPILER(MSVC)
+extern "C" HDC __stdcall _HBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
+extern "C" BOOL __stdcall _HEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint);
+#endif
+
+HDC WINAPI PluginView::hookedBeginPaint(HWND hWnd, PAINTSTRUCT* lpPaint)
+{
+ PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
+ if (pluginView && pluginView->m_wmPrintHDC) {
+ // We're secretly handling WM_PRINTCLIENT, so set up the PAINTSTRUCT so
+ // that the plugin will paint into the HDC we provide.
+ memset(lpPaint, 0, sizeof(PAINTSTRUCT));
+ lpPaint->hdc = pluginView->m_wmPrintHDC;
+ GetClientRect(hWnd, &lpPaint->rcPaint);
+ return pluginView->m_wmPrintHDC;
+ }
+
+#if COMPILER(GCC)
+ HDC result;
+ asm ("push %2\n"
+ "push %3\n"
+ "call *%4\n"
+ : "=a" (result)
+ : "a" (beginPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (beginPaint)
+ : "memory"
+ );
+ return result;
+#elif defined(_M_IX86)
+ // Call through to the original BeginPaint.
+ __asm mov eax, beginPaintSysCall
+ __asm push lpPaint
+ __asm push hWnd
+ __asm call beginPaint
+#else
+ return _HBeginPaint(hWnd, lpPaint);
+#endif
+}
+
+BOOL WINAPI PluginView::hookedEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
+{
+ PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
+ if (pluginView && pluginView->m_wmPrintHDC) {
+ // We're secretly handling WM_PRINTCLIENT, so we don't have to do any
+ // cleanup.
+ return TRUE;
+ }
+
+#if COMPILER(GCC)
+ BOOL result;
+ asm ("push %2\n"
+ "push %3\n"
+ "call *%4\n"
+ : "=a" (result)
+ : "a" (endPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (endPaint)
+ );
+ return result;
+#elif defined (_M_IX86)
+ // Call through to the original EndPaint.
+ __asm mov eax, endPaintSysCall
+ __asm push lpPaint
+ __asm push hWnd
+ __asm call endPaint
+#else
+ return _HEndPaint(hWnd, lpPaint);
+#endif
+}
+
+static void hook(const char* module, const char* proc, unsigned& sysCallID, BYTE*& pProc, const void* pNewProc)
+{
+ // See <http://www.fengyuan.com/article/wmprint.html> for an explanation of
+ // how this function works.
+
+ HINSTANCE hMod = GetModuleHandleA(module);
+
+ pProc = reinterpret_cast<BYTE*>(reinterpret_cast<ptrdiff_t>(GetProcAddress(hMod, proc)));
+
+#if COMPILER(GCC) || defined(_M_IX86)
+ if (pProc[0] != 0xB8)
+ return;
+
+ // FIXME: Should we be reading the bytes one-by-one instead of doing an
+ // unaligned read?
+ sysCallID = *reinterpret_cast<unsigned*>(pProc + 1);
+
+ DWORD flOldProtect;
+ if (!VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, &flOldProtect))
+ return;
+
+ pProc[0] = 0xE9;
+ *reinterpret_cast<unsigned*>(pProc + 1) = reinterpret_cast<intptr_t>(pNewProc) - reinterpret_cast<intptr_t>(pProc + 5);
+
+ pProc += 5;
+#else
+ /* Disassembly of BeginPaint()
+ 00000000779FC5B0 4C 8B D1 mov r10,rcx
+ 00000000779FC5B3 B8 17 10 00 00 mov eax,1017h
+ 00000000779FC5B8 0F 05 syscall
+ 00000000779FC5BA C3 ret
+ 00000000779FC5BB 90 nop
+ 00000000779FC5BC 90 nop
+ 00000000779FC5BD 90 nop
+ 00000000779FC5BE 90 nop
+ 00000000779FC5BF 90 nop
+ 00000000779FC5C0 90 nop
+ 00000000779FC5C1 90 nop
+ 00000000779FC5C2 90 nop
+ 00000000779FC5C3 90 nop
+ */
+ // Check for the signature as in the above disassembly
+ DWORD guard = 0xB8D18B4C;
+ if (*reinterpret_cast<DWORD*>(pProc) != guard)
+ return;
+
+ DWORD flOldProtect;
+ VirtualProtect(pProc, 12, PAGE_EXECUTE_READWRITE, & flOldProtect);
+ pProc[0] = 0x48; // mov rax, this
+ pProc[1] = 0xb8;
+ *(__int64*)(pProc+2) = (__int64)pNewProc;
+ pProc[10] = 0xff; // jmp rax
+ pProc[11] = 0xe0;
+#endif
+}
+
+static void setUpOffscreenPaintingHooks(HDC (WINAPI*hookedBeginPaint)(HWND, PAINTSTRUCT*), BOOL (WINAPI*hookedEndPaint)(HWND, const PAINTSTRUCT*))
+{
+ static bool haveHooked = false;
+ if (haveHooked)
+ return;
+ haveHooked = true;
+
+ // Most (all?) windowed plugins don't seem to respond to WM_PRINTCLIENT, so
+ // we hook into BeginPaint/EndPaint to allow their normal WM_PAINT handling
+ // to draw into a given HDC. Note that this hooking affects the entire
+ // process.
+ hook("user32.dll", "BeginPaint", beginPaintSysCall, beginPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedBeginPaint)));
+ hook("user32.dll", "EndPaint", endPaintSysCall, endPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedEndPaint)));
+
+}
+#endif
+
+static bool registerPluginView()
+{
+ static bool haveRegisteredWindowClass = false;
+ if (haveRegisteredWindowClass)
+ return true;
+
+ haveRegisteredWindowClass = true;
+
+#if PLATFORM(QT)
+ WebCore::setInstanceHandle((HINSTANCE)(qWinAppInst()));
+#endif
+
+ ASSERT(WebCore::instanceHandle());
+
+#if OS(WINCE)
+ WNDCLASS wcex = { 0 };
+#else
+ WNDCLASSEX wcex;
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.hIconSm = 0;
+#endif
+
+ wcex.style = CS_DBLCLKS;
+#if OS(WINCE)
+ wcex.style |= CS_PARENTDC;
+#endif
+ wcex.lpfnWndProc = DefWindowProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = WebCore::instanceHandle();
+ wcex.hIcon = 0;
+ wcex.hCursor = LoadCursor(0, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)COLOR_WINDOW;
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = kWebPluginViewdowClassName;
+
+#if OS(WINCE)
+ return !!RegisterClass(&wcex);
+#else
+ return !!RegisterClassEx(&wcex);
+#endif
+}
+
+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);
+ }
+
+#if !OS(WINCE)
+ if (message == WM_PRINTCLIENT) {
+ // Most (all?) windowed plugins don't respond to WM_PRINTCLIENT, so we
+ // change the message to WM_PAINT and rely on our hooked versions of
+ // BeginPaint/EndPaint to make the plugin draw into the given HDC.
+ message = WM_PAINT;
+ m_wmPrintHDC = reinterpret_cast<HDC>(wParam);
+ }
+#endif
+
+ // Call the plug-in's window proc.
+ LRESULT result = ::CallWindowProc(m_pluginWndProc, hWnd, message, wParam, lParam);
+
+ m_wmPrintHDC = 0;
+
+ m_isCallingPluginWndProc = false;
+
+ return result;
+}
+
+void PluginView::updatePluginWidget()
+{
+ if (!parent())
+ return;
+
+ ASSERT(parent()->isFrameView());
+ FrameView* frameView = static_cast<FrameView*>(parent());
+
+ IntRect oldWindowRect = m_windowRect;
+ IntRect oldClipRect = m_clipRect;
+
+#if OS(WINCE)
+ m_windowRect = frameView->contentsToWindow(frameRect());
+#else
+ m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
+#endif
+ m_clipRect = windowClipRect();
+ m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
+
+ if (platformPluginWidget() && (!m_haveUpdatedPluginWidget || 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_haveUpdatedPluginWidget || 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);
+
+ m_haveUpdatedPluginWidget = true;
+ }
+}
+
+void PluginView::setFocus(bool focused)
+{
+ if (focused && platformPluginWidget())
+ SetFocus(platformPluginWidget());
+
+ Widget::setFocus(focused);
+}
+
+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();
+}
+
+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(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+ bool result = m_plugin->pluginFuncs()->event(m_instance, &npEvent);
+ setCallingPlugin(false);
+
+ if (shouldPop)
+ popPopupsEnabledState();
+
+ return result;
+}
+
+void PluginView::paintIntoTransformedContext(HDC hdc)
+{
+ if (m_isWindowed) {
+#if !OS(WINCE)
+ SendMessage(platformPluginWidget(), WM_PRINTCLIENT, reinterpret_cast<WPARAM>(hdc), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED);
+#endif
+ return;
+ }
+
+ m_npWindow.type = NPWindowTypeDrawable;
+ m_npWindow.window = hdc;
+
+ WINDOWPOS windowpos = { 0, 0, 0, 0, 0, 0, 0 };
+
+ IntRect r = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
+
+ windowpos.x = r.x();
+ windowpos.y = r.y();
+ windowpos.cx = r.width();
+ windowpos.cy = r.height();
+
+ NPEvent npEvent;
+ npEvent.event = WM_WINDOWPOSCHANGED;
+ npEvent.lParam = reinterpret_cast<uintptr_t>(&windowpos);
+ npEvent.wParam = 0;
+
+ dispatchNPEvent(npEvent);
+
+ setNPWindowRect(frameRect());
+
+ npEvent.event = WM_PAINT;
+ npEvent.wParam = reinterpret_cast<uintptr_t>(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);
+}
+
+void PluginView::paintWindowedPluginIntoContext(GraphicsContext* context, const IntRect& rect)
+{
+#if !OS(WINCE)
+ ASSERT(m_isWindowed);
+ ASSERT(context->shouldIncludeChildWindows());
+
+ ASSERT(parent()->isFrameView());
+ IntPoint locationInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location());
+
+ LocalWindowsContext windowsContext(context, frameRect(), false);
+
+#if PLATFORM(CAIRO)
+ // Must flush drawings up to this point to the backing metafile, otherwise the
+ // plugin region will be overwritten with any clear regions specified in the
+ // cairo-controlled portions of the rendering.
+ PlatformGraphicsContext* ctx = context->platformContext();
+ cairo_show_page(ctx);
+#endif
+
+ HDC hdc = windowsContext.hdc();
+ XFORM originalTransform;
+ GetWorldTransform(hdc, &originalTransform);
+
+ // The plugin expects the DC to be in client coordinates, so we translate
+ // the DC to make that so.
+ AffineTransform ctm = context->getCTM();
+ ctm.translate(locationInWindow.x(), locationInWindow.y());
+ XFORM transform = static_cast<XFORM>(ctm.toTransformationMatrix());
+
+ SetWorldTransform(hdc, &transform);
+
+ paintIntoTransformedContext(hdc);
+
+ SetWorldTransform(hdc, &originalTransform);
+#endif
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_isStarted) {
+ // Draw the "missing plugin" image
+ paintMissingPluginIcon(context, rect);
+ return;
+ }
+
+ if (context->paintingDisabled())
+ return;
+
+ // Ensure that we have called SetWindow before we try to paint.
+ if (!m_haveCalledSetWindow)
+ setNPWindowRect(frameRect());
+
+ if (m_isWindowed) {
+#if !OS(WINCE)
+ if (context->shouldIncludeChildWindows())
+ paintWindowedPluginIntoContext(context, rect);
+#endif
+ return;
+ }
+
+ ASSERT(parent()->isFrameView());
+ IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
+ LocalWindowsContext windowsContext(context, rectInWindow, m_isTransparent);
+
+ // 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) && !OS(WINCE)
+ if (!context->inTransparencyLayer()) {
+ XFORM transform;
+ GetWorldTransform(windowsContext.hdc(), &transform);
+ transform.eDx = 0;
+ transform.eDy = 0;
+ SetWorldTransform(windowsContext.hdc(), &transform);
+ }
+#endif
+
+ paintIntoTransformedContext(windowsContext.hdc());
+}
+
+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(JSC::SilenceAssertionsOnly);
+ if (!dispatchNPEvent(npEvent))
+ event->setDefaultHandled();
+}
+
+#if !OS(WINCE)
+extern bool ignoreNextSetCursor;
+#endif
+
+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) {
+ focusPluginElement();
+ 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;
+
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ if (!dispatchNPEvent(npEvent))
+ event->setDefaultHandled();
+
+#if !PLATFORM(QT) && !PLATFORM(WX) && !OS(WINCE)
+ // 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;
+ if (Page* page = m_parentFrame->page())
+ page->chrome()->client()->setLastSetCursorToCurrentCursor();
+#endif
+}
+
+void PluginView::setParent(ScrollView* parent)
+{
+ Widget::setParent(parent);
+
+#if OS(WINCE)
+ if (parent) {
+ init();
+ if (parent->isVisible())
+ show();
+ else
+ hide();
+ }
+#else
+ 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);
+ }
+#endif
+}
+
+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;
+
+#if OS(WINCE)
+ IntRect r = static_cast<FrameView*>(parent())->contentsToWindow(rect);
+ m_npWindow.x = r.x();
+ m_npWindow.y = r.y();
+
+ m_npWindow.width = r.width();
+ m_npWindow.height = r.height();
+
+ m_npWindow.clipRect.right = r.width();
+ m_npWindow.clipRect.bottom = r.height();
+#else
+ 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.right = rect.width();
+ m_npWindow.clipRect.bottom = rect.height();
+#endif
+ m_npWindow.clipRect.left = 0;
+ m_npWindow.clipRect.top = 0;
+
+ if (m_plugin->pluginFuncs()->setwindow) {
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+
+ m_haveCalledSetWindow = true;
+
+ if (!m_isWindowed)
+ return;
+
+ ASSERT(platformPluginWidget());
+
+#if OS(WINCE)
+ if (!m_pluginWndProc) {
+ WNDPROC currentWndProc = (WNDPROC)GetWindowLong(platformPluginWidget(), GWL_WNDPROC);
+ if (currentWndProc != PluginViewWndProc)
+ m_pluginWndProc = (WNDPROC)SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)PluginViewWndProc);
+ }
+#else
+ WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
+ if (currentWndProc != PluginViewWndProc)
+ m_pluginWndProc = (WNDPROC)SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)PluginViewWndProc);
+#endif
+ }
+}
+
+NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t 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;
+}
+
+bool PluginView::platformGetValueStatic(NPNVariable, void*, NPError*)
+{
+ return false;
+}
+
+bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
+{
+ switch (variable) {
+ case NPNVnetscapeWindow: {
+ HWND* w = reinterpret_cast<HWND*>(value);
+ *w = windowHandleForPageClient(parent() ? parent()->hostWindow()->platformPageClient() : 0);
+ *result = NPERR_NO_ERROR;
+ return true;
+ }
+
+ case NPNVSupportsWindowless: {
+ NPBool* flag = reinterpret_cast<NPBool*>(value);
+ *flag = TRUE;
+ *result = NPERR_NO_ERROR;
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+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(windowHandleForPageClient(parent() ? parent()->hostWindow()->platformPageClient() : 0));
+}
+
+bool PluginView::platformStart()
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_status == PluginStatusLoadedSuccessfully);
+
+ if (m_isWindowed) {
+ registerPluginView();
+#if !OS(WINCE)
+ setUpOffscreenPaintingHooks(hookedBeginPaint, hookedEndPaint);
+#endif
+
+ DWORD flags = WS_CHILD;
+ if (isSelfVisible())
+ flags |= WS_VISIBLE;
+
+ HWND parentWindowHandle = windowHandleForPageClient(m_parentFrame->view()->hostWindow()->platformPageClient());
+ HWND window = ::CreateWindowEx(0, kWebPluginViewdowClassName, 0, flags,
+ 0, 0, 0, 0, parentWindowHandle, 0, WebCore::instanceHandle(), 0);
+
+#if OS(WINDOWS) && (PLATFORM(QT) || PLATFORM(WX))
+ 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 OS(WINDOWS) && CPU(X86_64)
+ ::SetWindowLongPtrA(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
+#elif OS(WINCE)
+ ::SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProc);
+#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;
+ }
+
+ updatePluginWidget();
+
+ if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))
+ setNPWindowRect(frameRect());
+
+ return true;
+}
+
+void PluginView::platformDestroy()
+{
+ if (!platformPluginWidget())
+ return;
+
+ DestroyWindow(platformPluginWidget());
+ setPlatformPluginWidget(0);
+}
+
+PassRefPtr<Image> PluginView::snapshot()
+{
+#if !PLATFORM(WX) && !OS(WINCE)
+ OwnPtr<HDC> hdc(CreateCompatibleDC(0));
+
+ if (!m_isWindowed) {
+ // Enable world transforms.
+ SetGraphicsMode(hdc.get(), GM_ADVANCED);
+
+ XFORM transform;
+ GetWorldTransform(hdc.get(), &transform);
+
+ // Windowless plug-ins assume that they're drawing onto the view's DC.
+ // Translate the context so that the plug-in draws at (0, 0).
+ ASSERT(parent()->isFrameView());
+ IntPoint position = static_cast<FrameView*>(parent())->contentsToWindow(frameRect()).location();
+ transform.eDx = -position.x();
+ transform.eDy = -position.y();
+ SetWorldTransform(hdc.get(), &transform);
+ }
+
+ void* bits;
+ BitmapInfo bmp = BitmapInfo::createBottomUp(frameRect().size());
+ OwnPtr<HBITMAP> hbmp(CreateDIBSection(0, &bmp, DIB_RGB_COLORS, &bits, 0, 0));
+
+ HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc.get(), hbmp.get()));
+
+ paintIntoTransformedContext(hdc.get());
+
+ SelectObject(hdc.get(), hbmpOld);
+
+ return BitmapImage::create(hbmp.get());
+#else
+ return 0;
+#endif
+}
+
+void PluginView::halt()
+{
+ ASSERT(!m_isHalted);
+ ASSERT(m_isStarted);
+
+#if !PLATFORM(QT)
+ // Show a screenshot of the plug-in.
+ toRenderWidget(m_element->renderer())->showSubstituteImage(snapshot());
+#endif
+
+ m_isHalted = true;
+ m_hasBeenHalted = true;
+
+ stop();
+ platformDestroy();
+}
+
+void PluginView::restart()
+{
+ ASSERT(!m_isStarted);
+ ASSERT(m_isHalted);
+
+ // Clear any substitute image.
+ toRenderWidget(m_element->renderer())->showSubstituteImage(0);
+
+ m_isHalted = false;
+ m_haveUpdatedPluginWidget = false;
+ start();
+}
+
+} // namespace WebCore