summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/plugins
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
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')
-rw-r--r--Source/WebCore/plugins/DOMMimeType.cpp78
-rw-r--r--Source/WebCore/plugins/DOMMimeType.h59
-rw-r--r--Source/WebCore/plugins/DOMMimeType.idl30
-rw-r--r--Source/WebCore/plugins/DOMMimeTypeArray.cpp95
-rw-r--r--Source/WebCore/plugins/DOMMimeTypeArray.h56
-rw-r--r--Source/WebCore/plugins/DOMMimeTypeArray.idl32
-rw-r--r--Source/WebCore/plugins/DOMPlugin.cpp96
-rw-r--r--Source/WebCore/plugins/DOMPlugin.h62
-rw-r--r--Source/WebCore/plugins/DOMPlugin.idl35
-rw-r--r--Source/WebCore/plugins/DOMPluginArray.cpp100
-rw-r--r--Source/WebCore/plugins/DOMPluginArray.h58
-rw-r--r--Source/WebCore/plugins/DOMPluginArray.idl33
-rw-r--r--Source/WebCore/plugins/PluginData.cpp81
-rw-r--r--Source/WebCore/plugins/PluginData.h75
-rw-r--r--Source/WebCore/plugins/PluginDataNone.cpp40
-rw-r--r--Source/WebCore/plugins/PluginDatabase.cpp675
-rw-r--r--Source/WebCore/plugins/PluginDatabase.h125
-rw-r--r--Source/WebCore/plugins/PluginDebug.cpp176
-rw-r--r--Source/WebCore/plugins/PluginDebug.h55
-rw-r--r--Source/WebCore/plugins/PluginMainThreadScheduler.cpp116
-rw-r--r--Source/WebCore/plugins/PluginMainThreadScheduler.h86
-rw-r--r--Source/WebCore/plugins/PluginPackage.cpp394
-rw-r--r--Source/WebCore/plugins/PluginPackage.h149
-rw-r--r--Source/WebCore/plugins/PluginPackageNone.cpp52
-rw-r--r--Source/WebCore/plugins/PluginQuirkSet.h65
-rw-r--r--Source/WebCore/plugins/PluginStrategy.h50
-rw-r--r--Source/WebCore/plugins/PluginStream.cpp508
-rw-r--r--Source/WebCore/plugins/PluginStream.h125
-rw-r--r--Source/WebCore/plugins/PluginView.cpp1620
-rw-r--r--Source/WebCore/plugins/PluginView.h503
-rw-r--r--Source/WebCore/plugins/PluginViewBase.h59
-rw-r--r--Source/WebCore/plugins/PluginViewNone.cpp167
-rw-r--r--Source/WebCore/plugins/chromium/PluginDataChromium.cpp97
-rw-r--r--Source/WebCore/plugins/chromium/PluginDataChromium.h39
-rw-r--r--Source/WebCore/plugins/gtk/PluginDataGtk.cpp65
-rw-r--r--Source/WebCore/plugins/gtk/PluginPackageGtk.cpp176
-rw-r--r--Source/WebCore/plugins/gtk/PluginViewGtk.cpp901
-rw-r--r--Source/WebCore/plugins/gtk/gtk2xtbin.c966
-rw-r--r--Source/WebCore/plugins/gtk/gtk2xtbin.h158
-rw-r--r--Source/WebCore/plugins/gtk/xembed.h64
-rw-r--r--Source/WebCore/plugins/mac/PluginPackageMac.cpp307
-rw-r--r--Source/WebCore/plugins/mac/PluginViewMac.mm821
-rw-r--r--Source/WebCore/plugins/npapi.cpp206
-rw-r--r--Source/WebCore/plugins/npfunctions.h219
-rw-r--r--Source/WebCore/plugins/qt/PluginContainerQt.cpp150
-rw-r--r--Source/WebCore/plugins/qt/PluginContainerQt.h63
-rw-r--r--Source/WebCore/plugins/qt/PluginPackageQt.cpp199
-rw-r--r--Source/WebCore/plugins/qt/PluginViewQt.cpp1011
-rw-r--r--Source/WebCore/plugins/symbian/PluginContainerSymbian.cpp77
-rw-r--r--Source/WebCore/plugins/symbian/PluginContainerSymbian.h53
-rw-r--r--Source/WebCore/plugins/symbian/PluginDatabaseSymbian.cpp79
-rw-r--r--Source/WebCore/plugins/symbian/PluginPackageSymbian.cpp182
-rw-r--r--Source/WebCore/plugins/symbian/PluginViewSymbian.cpp441
-rw-r--r--Source/WebCore/plugins/symbian/npinterface.h37
-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
-rw-r--r--Source/WebCore/plugins/wx/PluginDataWx.cpp70
61 files changed, 14384 insertions, 0 deletions
diff --git a/Source/WebCore/plugins/DOMMimeType.cpp b/Source/WebCore/plugins/DOMMimeType.cpp
new file mode 100644
index 0000000..114d218
--- /dev/null
+++ b/Source/WebCore/plugins/DOMMimeType.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "DOMMimeType.h"
+
+#include "DOMPlugin.h"
+#include "Frame.h"
+#include "FrameLoaderClient.h"
+#include "Page.h"
+#include "PluginData.h"
+#include "Settings.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+DOMMimeType::DOMMimeType(PassRefPtr<PluginData> pluginData, Frame* frame, unsigned index)
+ : m_pluginData(pluginData)
+ , m_frame(frame)
+ , m_index(index)
+{
+ if (m_frame)
+ m_frame->addDestructionObserver(this);
+}
+
+DOMMimeType::~DOMMimeType()
+{
+ if (m_frame)
+ m_frame->removeDestructionObserver(this);
+}
+
+const String &DOMMimeType::type() const
+{
+ return mimeClassInfo().type;
+}
+
+String DOMMimeType::suffixes() const
+{
+ const Vector<String>& extensions = mimeClassInfo().extensions;
+
+ StringBuilder builder;
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ if (i)
+ builder.append(',');
+ builder.append(extensions[i]);
+ }
+ return builder.toString();
+}
+
+const String &DOMMimeType::description() const
+{
+ return mimeClassInfo().desc;
+}
+
+PassRefPtr<DOMPlugin> DOMMimeType::enabledPlugin() const
+{
+ if (!m_frame || !m_frame->page() || !m_frame->page()->mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
+ return 0;
+
+ return DOMPlugin::create(m_pluginData.get(), m_frame, m_pluginData->mimePluginIndices()[m_index]);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/DOMMimeType.h b/Source/WebCore/plugins/DOMMimeType.h
new file mode 100644
index 0000000..74c62d0
--- /dev/null
+++ b/Source/WebCore/plugins/DOMMimeType.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2008 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.
+*/
+
+#ifndef DOMMimeType_h
+#define DOMMimeType_h
+
+#include "Frame.h"
+#include "PluginData.h"
+
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class DOMPlugin;
+
+class DOMMimeType : public RefCounted<DOMMimeType>, private FrameDestructionObserver {
+public:
+ static PassRefPtr<DOMMimeType> create(PassRefPtr<PluginData> pluginData, Frame* frame, unsigned index) { return adoptRef(new DOMMimeType(pluginData, frame, index)); }
+ ~DOMMimeType();
+
+ const String &type() const;
+ String suffixes() const;
+ const String &description() const;
+ PassRefPtr<DOMPlugin> enabledPlugin() const;
+
+ // FrameDestructionObserver
+ virtual void frameDestroyed() { m_frame = 0; }
+
+private:
+ const MimeClassInfo& mimeClassInfo() const { return m_pluginData->mimes()[m_index]; }
+
+ DOMMimeType(PassRefPtr<PluginData>, Frame*, unsigned index);
+ RefPtr<PluginData> m_pluginData;
+ Frame* m_frame;
+ unsigned m_index;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/plugins/DOMMimeType.idl b/Source/WebCore/plugins/DOMMimeType.idl
new file mode 100644
index 0000000..1d97a6b
--- /dev/null
+++ b/Source/WebCore/plugins/DOMMimeType.idl
@@ -0,0 +1,30 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 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.
+*/
+
+module window {
+
+ interface DOMMimeType {
+ readonly attribute DOMString type;
+ readonly attribute DOMString suffixes;
+ readonly attribute DOMString description;
+ readonly attribute DOMPlugin enabledPlugin;
+ };
+
+}
diff --git a/Source/WebCore/plugins/DOMMimeTypeArray.cpp b/Source/WebCore/plugins/DOMMimeTypeArray.cpp
new file mode 100644
index 0000000..82d4006
--- /dev/null
+++ b/Source/WebCore/plugins/DOMMimeTypeArray.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "DOMMimeTypeArray.h"
+
+#include "DOMPlugin.h"
+#include "Frame.h"
+#include "Page.h"
+#include "PluginData.h"
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+DOMMimeTypeArray::DOMMimeTypeArray(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+DOMMimeTypeArray::~DOMMimeTypeArray()
+{
+}
+
+unsigned DOMMimeTypeArray::length() const
+{
+ PluginData* data = getPluginData();
+ if (!data)
+ return 0;
+ return data->mimes().size();
+}
+
+PassRefPtr<DOMMimeType> DOMMimeTypeArray::item(unsigned index)
+{
+ PluginData* data = getPluginData();
+ if (!data)
+ return 0;
+ const Vector<MimeClassInfo>& mimes = data->mimes();
+ if (index >= mimes.size())
+ return 0;
+ return DOMMimeType::create(data, m_frame, index).get();
+}
+
+bool DOMMimeTypeArray::canGetItemsForName(const AtomicString& propertyName)
+{
+ PluginData *data = getPluginData();
+ if (!data)
+ return 0;
+ const Vector<MimeClassInfo>& mimes = data->mimes();
+ for (unsigned i = 0; i < mimes.size(); ++i) {
+ if (mimes[i].type == propertyName)
+ return true;
+ }
+ return false;
+}
+
+PassRefPtr<DOMMimeType> DOMMimeTypeArray::namedItem(const AtomicString& propertyName)
+{
+ PluginData *data = getPluginData();
+ if (!data)
+ return 0;
+ const Vector<MimeClassInfo>& mimes = data->mimes();
+ for (unsigned i = 0; i < mimes.size(); ++i) {
+ if (mimes[i].type == propertyName)
+ return DOMMimeType::create(data, m_frame, i).get();
+ }
+ return 0;
+}
+
+PluginData* DOMMimeTypeArray::getPluginData() const
+{
+ if (!m_frame)
+ return 0;
+ Page* p = m_frame->page();
+ if (!p)
+ return 0;
+ return p->pluginData();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/DOMMimeTypeArray.h b/Source/WebCore/plugins/DOMMimeTypeArray.h
new file mode 100644
index 0000000..ed078bb
--- /dev/null
+++ b/Source/WebCore/plugins/DOMMimeTypeArray.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 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.
+*/
+
+#ifndef DOMMimeTypeArray_h
+#define DOMMimeTypeArray_h
+
+#include "DOMMimeType.h"
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Frame;
+class PluginData;
+
+class DOMMimeTypeArray : public RefCounted<DOMMimeTypeArray> {
+public:
+ static PassRefPtr<DOMMimeTypeArray> create(Frame* frame) { return adoptRef(new DOMMimeTypeArray(frame)); }
+ ~DOMMimeTypeArray();
+
+ void disconnectFrame() { m_frame = 0; }
+
+ unsigned length() const;
+ PassRefPtr<DOMMimeType> item(unsigned index);
+ bool canGetItemsForName(const AtomicString& propertyName);
+ PassRefPtr<DOMMimeType> namedItem(const AtomicString& propertyName);
+
+private:
+ DOMMimeTypeArray(Frame*);
+ PluginData* getPluginData() const;
+
+ Frame* m_frame;
+};
+
+} // namespace WebCore
+
+#endif // MimeTypeArray_h
diff --git a/Source/WebCore/plugins/DOMMimeTypeArray.idl b/Source/WebCore/plugins/DOMMimeTypeArray.idl
new file mode 100644
index 0000000..8b79a7e
--- /dev/null
+++ b/Source/WebCore/plugins/DOMMimeTypeArray.idl
@@ -0,0 +1,32 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 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.
+*/
+
+module window {
+
+ interface [
+ HasNameGetter,
+ HasIndexGetter
+ ] DOMMimeTypeArray {
+ readonly attribute unsigned long length;
+ DOMMimeType item(in unsigned long index);
+ DOMMimeType namedItem(in DOMString name);
+ };
+
+}
diff --git a/Source/WebCore/plugins/DOMPlugin.cpp b/Source/WebCore/plugins/DOMPlugin.cpp
new file mode 100644
index 0000000..8ddb507
--- /dev/null
+++ b/Source/WebCore/plugins/DOMPlugin.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "DOMPlugin.h"
+
+#include "PluginData.h"
+#include "Frame.h"
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+DOMPlugin::DOMPlugin(PluginData* pluginData, Frame* frame, unsigned index)
+ : m_pluginData(pluginData)
+ , m_frame(frame)
+ , m_index(index)
+{
+ if (m_frame)
+ m_frame->addDestructionObserver(this);
+}
+
+DOMPlugin::~DOMPlugin()
+{
+ if (m_frame)
+ m_frame->removeDestructionObserver(this);
+}
+
+String DOMPlugin::name() const
+{
+ return pluginInfo().name;
+}
+
+String DOMPlugin::filename() const
+{
+ return pluginInfo().file;
+}
+
+String DOMPlugin::description() const
+{
+ return pluginInfo().desc;
+}
+
+unsigned DOMPlugin::length() const
+{
+ return pluginInfo().mimes.size();
+}
+
+PassRefPtr<DOMMimeType> DOMPlugin::item(unsigned index)
+{
+ if (index >= pluginInfo().mimes.size())
+ return 0;
+
+ const MimeClassInfo& mime = pluginInfo().mimes[index];
+
+ const Vector<MimeClassInfo>& mimes = m_pluginData->mimes();
+ for (unsigned i = 0; i < mimes.size(); ++i) {
+ if (mimes[i] == mime && m_pluginData->mimePluginIndices()[i] == m_index)
+ return DOMMimeType::create(m_pluginData.get(), m_frame, i).get();
+ }
+ return 0;
+}
+
+bool DOMPlugin::canGetItemsForName(const AtomicString& propertyName)
+{
+ const Vector<MimeClassInfo>& mimes = m_pluginData->mimes();
+ for (unsigned i = 0; i < mimes.size(); ++i)
+ if (mimes[i].type == propertyName)
+ return true;
+ return false;
+}
+
+PassRefPtr<DOMMimeType> DOMPlugin::namedItem(const AtomicString& propertyName)
+{
+ const Vector<MimeClassInfo>& mimes = m_pluginData->mimes();
+ for (unsigned i = 0; i < mimes.size(); ++i)
+ if (mimes[i].type == propertyName)
+ return DOMMimeType::create(m_pluginData.get(), m_frame, i).get();
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/DOMPlugin.h b/Source/WebCore/plugins/DOMPlugin.h
new file mode 100644
index 0000000..f305ec2
--- /dev/null
+++ b/Source/WebCore/plugins/DOMPlugin.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2008 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.
+*/
+
+#ifndef DOMPlugin_h
+#define DOMPlugin_h
+
+#include "DOMMimeType.h"
+#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class Plugin;
+class PluginData;
+
+class DOMPlugin : public RefCounted<DOMPlugin>, private FrameDestructionObserver {
+public:
+ static PassRefPtr<DOMPlugin> create(PluginData* pluginData, Frame* frame, unsigned index) { return adoptRef(new DOMPlugin(pluginData, frame, index)); }
+ ~DOMPlugin();
+
+ String name() const;
+ String filename() const;
+ String description() const;
+
+ unsigned length() const;
+
+ PassRefPtr<DOMMimeType> item(unsigned index);
+ bool canGetItemsForName(const AtomicString& propertyName);
+ PassRefPtr<DOMMimeType> namedItem(const AtomicString& propertyName);
+
+ // FrameDestructionObserver
+ virtual void frameDestroyed() { m_frame = 0; }
+
+private:
+ const PluginInfo& pluginInfo() const { return m_pluginData->plugins()[m_index]; }
+
+ DOMPlugin(PluginData*, Frame*, unsigned index);
+ RefPtr<PluginData> m_pluginData;
+ Frame* m_frame;
+ unsigned m_index;
+};
+
+} // namespace WebCore
+
+#endif // Plugin_h
diff --git a/Source/WebCore/plugins/DOMPlugin.idl b/Source/WebCore/plugins/DOMPlugin.idl
new file mode 100644
index 0000000..dc2b141
--- /dev/null
+++ b/Source/WebCore/plugins/DOMPlugin.idl
@@ -0,0 +1,35 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 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.
+*/
+
+module window {
+
+ interface [
+ HasNameGetter,
+ HasIndexGetter
+ ] DOMPlugin {
+ readonly attribute DOMString name;
+ readonly attribute DOMString filename;
+ readonly attribute DOMString description;
+ readonly attribute unsigned long length;
+ DOMMimeType item(in unsigned long index);
+ DOMMimeType namedItem(in DOMString name);
+ };
+
+}
diff --git a/Source/WebCore/plugins/DOMPluginArray.cpp b/Source/WebCore/plugins/DOMPluginArray.cpp
new file mode 100644
index 0000000..766c3eb
--- /dev/null
+++ b/Source/WebCore/plugins/DOMPluginArray.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "DOMPluginArray.h"
+
+#include "DOMPlugin.h"
+#include "Frame.h"
+#include "Page.h"
+#include "PluginData.h"
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+DOMPluginArray::DOMPluginArray(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+DOMPluginArray::~DOMPluginArray()
+{
+}
+
+unsigned DOMPluginArray::length() const
+{
+ PluginData* data = pluginData();
+ if (!data)
+ return 0;
+ return data->plugins().size();
+}
+
+PassRefPtr<DOMPlugin> DOMPluginArray::item(unsigned index)
+{
+ PluginData* data = pluginData();
+ if (!data)
+ return 0;
+ const Vector<PluginInfo>& plugins = data->plugins();
+ if (index >= plugins.size())
+ return 0;
+ return DOMPlugin::create(data, m_frame, index).get();
+}
+
+bool DOMPluginArray::canGetItemsForName(const AtomicString& propertyName)
+{
+ PluginData* data = pluginData();
+ if (!data)
+ return 0;
+ const Vector<PluginInfo>& plugins = data->plugins();
+ for (unsigned i = 0; i < plugins.size(); ++i) {
+ if (plugins[i].name == propertyName)
+ return true;
+ }
+ return false;
+}
+
+PassRefPtr<DOMPlugin> DOMPluginArray::namedItem(const AtomicString& propertyName)
+{
+ PluginData* data = pluginData();
+ if (!data)
+ return 0;
+ const Vector<PluginInfo>& plugins = data->plugins();
+ for (unsigned i = 0; i < plugins.size(); ++i) {
+ if (plugins[i].name == propertyName)
+ return DOMPlugin::create(data, m_frame, i).get();
+ }
+ return 0;
+}
+
+void DOMPluginArray::refresh(bool reload)
+{
+ Page::refreshPlugins(reload);
+}
+
+PluginData* DOMPluginArray::pluginData() const
+{
+ if (!m_frame)
+ return 0;
+ Page* page = m_frame->page();
+ if (!page)
+ return 0;
+ return page->pluginData();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/DOMPluginArray.h b/Source/WebCore/plugins/DOMPluginArray.h
new file mode 100644
index 0000000..cc70572
--- /dev/null
+++ b/Source/WebCore/plugins/DOMPluginArray.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 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.
+*/
+
+#ifndef DOMPluginArray_h
+#define DOMPluginArray_h
+
+#include "DOMPlugin.h"
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Frame;
+class PluginData;
+
+class DOMPluginArray : public RefCounted<DOMPluginArray> {
+public:
+ static PassRefPtr<DOMPluginArray> create(Frame* frame) { return adoptRef(new DOMPluginArray(frame)); }
+ ~DOMPluginArray();
+
+ void disconnectFrame() { m_frame = 0; }
+
+ unsigned length() const;
+ PassRefPtr<DOMPlugin> item(unsigned index);
+ bool canGetItemsForName(const AtomicString& propertyName);
+ PassRefPtr<DOMPlugin> namedItem(const AtomicString& propertyName);
+
+ void refresh(bool reload);
+
+private:
+ DOMPluginArray(Frame*);
+ PluginData* pluginData() const;
+
+ Frame* m_frame;
+};
+
+} // namespace WebCore
+
+#endif // PluginArray_h
diff --git a/Source/WebCore/plugins/DOMPluginArray.idl b/Source/WebCore/plugins/DOMPluginArray.idl
new file mode 100644
index 0000000..4c0d64c
--- /dev/null
+++ b/Source/WebCore/plugins/DOMPluginArray.idl
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 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.
+*/
+
+module window {
+
+ interface [
+ HasNameGetter,
+ HasIndexGetter
+ ] DOMPluginArray {
+ readonly attribute unsigned long length;
+ DOMPlugin item(in unsigned long index);
+ DOMPlugin namedItem(in DOMString name);
+ void refresh(in boolean reload);
+ };
+
+}
diff --git a/Source/WebCore/plugins/PluginData.cpp b/Source/WebCore/plugins/PluginData.cpp
new file mode 100644
index 0000000..b8e751d
--- /dev/null
+++ b/Source/WebCore/plugins/PluginData.cpp
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2000 Harri Porten (porten@kde.org)
+ Copyright (C) 2000 Daniel Molkentin (molkentin@kde.org)
+ Copyright (C) 2000 Stefan Schimanski (schimmi@kde.org)
+ Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All Rights Reserved.
+ Copyright (C) 2008 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.
+*/
+
+#include "config.h"
+#include "PluginData.h"
+
+#if USE(PLATFORM_STRATEGIES)
+#include "PlatformStrategies.h"
+#include "PluginStrategy.h"
+#endif
+
+namespace WebCore {
+
+PluginData::PluginData(const Page* page)
+{
+ initPlugins(page);
+
+ for (unsigned i = 0; i < m_plugins.size(); ++i) {
+ const PluginInfo& plugin = m_plugins[i];
+ for (unsigned j = 0; j < plugin.mimes.size(); ++j) {
+ m_mimes.append(plugin.mimes[j]);
+ m_mimePluginIndices.append(i);
+ }
+ }
+}
+
+bool PluginData::supportsMimeType(const String& mimeType) const
+{
+ for (unsigned i = 0; i < m_mimes.size(); ++i)
+ if (m_mimes[i].type == mimeType)
+ return true;
+ return false;
+}
+
+String PluginData::pluginNameForMimeType(const String& mimeType) const
+{
+ for (unsigned i = 0; i < m_mimes.size(); ++i) {
+ const MimeClassInfo& info = m_mimes[i];
+
+ if (info.type == mimeType)
+ return m_plugins[m_mimePluginIndices[i]].name;
+ }
+
+ return String();
+}
+
+#if USE(PLATFORM_STRATEGIES)
+void PluginData::refresh()
+{
+ platformStrategies()->pluginStrategy()->refreshPlugins();
+}
+
+void PluginData::initPlugins(const Page* page)
+{
+ ASSERT(m_plugins.isEmpty());
+
+ platformStrategies()->pluginStrategy()->getPluginInfo(page, m_plugins);
+}
+#endif
+
+}
diff --git a/Source/WebCore/plugins/PluginData.h b/Source/WebCore/plugins/PluginData.h
new file mode 100644
index 0000000..c6cde81
--- /dev/null
+++ b/Source/WebCore/plugins/PluginData.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2008 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.
+*/
+
+#ifndef PluginData_h
+#define PluginData_h
+
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class Page;
+struct PluginInfo;
+
+struct MimeClassInfo {
+ String type;
+ String desc;
+ Vector<String> extensions;
+};
+
+inline bool operator==(const MimeClassInfo& a, const MimeClassInfo& b)
+{
+ return a.type == b.type && a.desc == b.desc && a.extensions == b.extensions;
+}
+
+struct PluginInfo {
+ String name;
+ String file;
+ String desc;
+ Vector<MimeClassInfo> mimes;
+};
+
+// FIXME: merge with PluginDatabase in the future
+class PluginData : public RefCounted<PluginData> {
+public:
+ static PassRefPtr<PluginData> create(const Page* page) { return adoptRef(new PluginData(page)); }
+
+ const Vector<PluginInfo>& plugins() const { return m_plugins; }
+ const Vector<MimeClassInfo>& mimes() const { return m_mimes; }
+ const Vector<size_t>& mimePluginIndices() const { return m_mimePluginIndices; }
+
+ bool supportsMimeType(const String& mimeType) const;
+ String pluginNameForMimeType(const String& mimeType) const;
+
+ static void refresh();
+
+private:
+ PluginData(const Page*);
+ void initPlugins(const Page*);
+
+ Vector<PluginInfo> m_plugins;
+ Vector<MimeClassInfo> m_mimes;
+ Vector<size_t> m_mimePluginIndices;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/plugins/PluginDataNone.cpp b/Source/WebCore/plugins/PluginDataNone.cpp
new file mode 100644
index 0000000..edfee5b
--- /dev/null
+++ b/Source/WebCore/plugins/PluginDataNone.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> 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 "PluginData.h"
+
+namespace WebCore {
+
+void PluginData::initPlugins(const Page*)
+{
+}
+
+void PluginData::refresh()
+{
+}
+
+};
diff --git a/Source/WebCore/plugins/PluginDatabase.cpp b/Source/WebCore/plugins/PluginDatabase.cpp
new file mode 100644
index 0000000..b9e154a
--- /dev/null
+++ b/Source/WebCore/plugins/PluginDatabase.cpp
@@ -0,0 +1,675 @@
+/*
+ * 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"
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+#include "FileSystem.h"
+#endif
+#include <stdlib.h>
+#include <wtf/text/CString.h>
+
+#if PLATFORM(ANDROID)
+#include "JavaSharedClient.h"
+#include "PluginClient.h"
+#endif
+
+namespace WebCore {
+
+typedef HashMap<String, RefPtr<PluginPackage> > PluginPackageByNameMap;
+
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+static const size_t maximumPersistentPluginMetadataCacheSize = 32768;
+
+static bool gPersistentPluginMetadataCacheIsEnabled;
+
+String& persistentPluginMetadataCachePath()
+{
+ DEFINE_STATIC_LOCAL(String, cachePath, ());
+ return cachePath;
+}
+#endif
+
+PluginDatabase::PluginDatabase()
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ : m_persistentMetadataCacheIsLoaded(false)
+#endif
+{
+}
+
+PluginDatabase* PluginDatabase::installedPlugins(bool populate)
+{
+ static PluginDatabase* plugins = 0;
+
+ if (!plugins) {
+ plugins = new PluginDatabase;
+
+ if (populate) {
+ plugins->setPluginDirectories(PluginDatabase::defaultPluginDirectories());
+ plugins->refresh();
+ }
+ }
+
+ return plugins;
+}
+
+bool PluginDatabase::isMIMETypeRegistered(const String& mimeType)
+{
+ if (mimeType.isNull())
+ return false;
+ if (m_registeredMIMETypes.contains(mimeType))
+ return true;
+ // No plugin was found, try refreshing the database and searching again
+ return (refresh() && m_registeredMIMETypes.contains(mimeType));
+}
+
+void PluginDatabase::addExtraPluginDirectory(const String& directory)
+{
+ m_pluginDirectories.append(directory);
+ refresh();
+}
+
+bool PluginDatabase::refresh()
+{
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ if (!m_persistentMetadataCacheIsLoaded)
+ loadPersistentMetadataCache();
+#endif
+ bool pluginSetChanged = false;
+
+ if (!m_plugins.isEmpty()) {
+ PluginSet pluginsToUnload;
+ getDeletedPlugins(pluginsToUnload);
+
+ // Unload plugins
+ PluginSet::const_iterator end = pluginsToUnload.end();
+ for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it)
+ remove(it->get());
+
+ pluginSetChanged = !pluginsToUnload.isEmpty();
+ }
+
+ HashSet<String> paths;
+ getPluginPathsInDirectories(paths);
+
+ HashMap<String, time_t> pathsWithTimes;
+
+ // We should only skip unchanged files if we didn't remove any plugins above. If we did remove
+ // any plugins, we need to look at every plugin file so that, e.g., if the user has two versions
+ // of RealPlayer installed and just removed the newer one, we'll pick up the older one.
+ bool shouldSkipUnchangedFiles = !pluginSetChanged;
+
+ HashSet<String>::const_iterator pathsEnd = paths.end();
+ for (HashSet<String>::const_iterator it = paths.begin(); it != pathsEnd; ++it) {
+ time_t lastModified;
+ if (!getFileModificationTime(*it, lastModified))
+ continue;
+
+ pathsWithTimes.add(*it, lastModified);
+
+ // If the path's timestamp hasn't changed since the last time we ran refresh(), we don't have to do anything.
+ if (shouldSkipUnchangedFiles && m_pluginPathsWithTimes.get(*it) == lastModified)
+ continue;
+
+ if (RefPtr<PluginPackage> oldPackage = m_pluginsByPath.get(*it)) {
+ ASSERT(!shouldSkipUnchangedFiles || oldPackage->lastModified() != lastModified);
+ remove(oldPackage.get());
+ }
+
+ RefPtr<PluginPackage> package = PluginPackage::createPackage(*it, lastModified);
+ if (package && add(package.release()))
+ pluginSetChanged = true;
+ }
+
+ // Cache all the paths we found with their timestamps for next time.
+ pathsWithTimes.swap(m_pluginPathsWithTimes);
+
+ if (!pluginSetChanged)
+ return false;
+
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ updatePersistentMetadataCache();
+#endif
+
+ m_registeredMIMETypes.clear();
+
+ // Register plug-in MIME types
+ PluginSet::const_iterator end = m_plugins.end();
+ for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
+ // Get MIME types
+ MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin();
+ MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end();
+ for (; map_it != map_end; ++map_it)
+ m_registeredMIMETypes.add(map_it->first);
+ }
+
+ return true;
+}
+
+Vector<PluginPackage*> PluginDatabase::plugins() const
+{
+ Vector<PluginPackage*> result;
+
+ PluginSet::const_iterator end = m_plugins.end();
+ for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it)
+ result.append((*it).get());
+
+ return result;
+}
+
+int PluginDatabase::preferredPluginCompare(const void* a, const void* b)
+{
+ PluginPackage* pluginA = *static_cast<PluginPackage* const*>(a);
+ PluginPackage* pluginB = *static_cast<PluginPackage* const*>(b);
+
+ return pluginA->compare(*pluginB);
+}
+
+PluginPackage* PluginDatabase::pluginForMIMEType(const String& mimeType)
+{
+ if (mimeType.isEmpty())
+ return 0;
+
+ String key = mimeType.lower();
+ PluginSet::const_iterator end = m_plugins.end();
+ PluginPackage* preferredPlugin = m_preferredPlugins.get(key).get();
+ if (preferredPlugin
+ && preferredPlugin->isEnabled()
+ && preferredPlugin->mimeToDescriptions().contains(key)) {
+ return preferredPlugin;
+ }
+
+ Vector<PluginPackage*, 2> pluginChoices;
+
+ for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
+ PluginPackage* plugin = (*it).get();
+
+ if (!plugin->isEnabled())
+ continue;
+
+ if (plugin->mimeToDescriptions().contains(key)) {
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ if (!plugin->ensurePluginLoaded())
+ continue;
+#endif
+ pluginChoices.append(plugin);
+ }
+ }
+
+ if (pluginChoices.isEmpty())
+ return 0;
+
+ qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare);
+
+ return pluginChoices[0];
+}
+
+String PluginDatabase::MIMETypeForExtension(const String& extension) const
+{
+ if (extension.isEmpty())
+ return String();
+
+ PluginSet::const_iterator end = m_plugins.end();
+ String mimeType;
+ Vector<PluginPackage*, 2> pluginChoices;
+ HashMap<PluginPackage*, String> mimeTypeForPlugin;
+
+ for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
+ if (!(*it)->isEnabled())
+ continue;
+
+ MIMEToExtensionsMap::const_iterator mime_end = (*it)->mimeToExtensions().end();
+
+ for (MIMEToExtensionsMap::const_iterator mime_it = (*it)->mimeToExtensions().begin(); mime_it != mime_end; ++mime_it) {
+ mimeType = mime_it->first;
+ PluginPackage* preferredPlugin = m_preferredPlugins.get(mimeType).get();
+ const Vector<String>& extensions = mime_it->second;
+ bool foundMapping = false;
+ for (unsigned i = 0; i < extensions.size(); i++) {
+ if (equalIgnoringCase(extensions[i], extension)) {
+ PluginPackage* plugin = (*it).get();
+
+ if (preferredPlugin && PluginPackage::equal(*plugin, *preferredPlugin))
+ return mimeType;
+
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ if (!plugin->ensurePluginLoaded())
+ continue;
+#endif
+ pluginChoices.append(plugin);
+ mimeTypeForPlugin.add(plugin, mimeType);
+ foundMapping = true;
+ break;
+ }
+ }
+ if (foundMapping)
+ break;
+ }
+ }
+
+ if (pluginChoices.isEmpty())
+ return String();
+
+ qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare);
+
+ return mimeTypeForPlugin.get(pluginChoices[0]);
+}
+
+PluginPackage* PluginDatabase::findPlugin(const KURL& url, String& mimeType)
+{
+ if (!mimeType.isEmpty())
+ return pluginForMIMEType(mimeType);
+
+ String filename = url.lastPathComponent();
+ if (filename.endsWith("/"))
+ return 0;
+
+ int extensionPos = filename.reverseFind('.');
+ if (extensionPos == -1)
+ return 0;
+
+ String mimeTypeForExtension = MIMETypeForExtension(filename.substring(extensionPos + 1));
+ PluginPackage* plugin = pluginForMIMEType(mimeTypeForExtension);
+ if (!plugin) {
+ // FIXME: if no plugin could be found, query Windows for the mime type
+ // corresponding to the extension.
+ return 0;
+ }
+
+ mimeType = mimeTypeForExtension;
+ return plugin;
+}
+
+void PluginDatabase::setPreferredPluginForMIMEType(const String& mimeType, PluginPackage* plugin)
+{
+ if (!plugin || plugin->mimeToExtensions().contains(mimeType))
+ m_preferredPlugins.set(mimeType.lower(), plugin);
+}
+
+void PluginDatabase::getDeletedPlugins(PluginSet& plugins) const
+{
+ PluginSet::const_iterator end = m_plugins.end();
+ for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
+ if (!fileExists((*it)->path()))
+ plugins.add(*it);
+ }
+}
+
+bool PluginDatabase::add(PassRefPtr<PluginPackage> prpPackage)
+{
+ ASSERT_ARG(prpPackage, prpPackage);
+
+ RefPtr<PluginPackage> package = prpPackage;
+
+ if (!m_plugins.add(package).second)
+ return false;
+
+ m_pluginsByPath.add(package->path(), package);
+ return true;
+}
+
+void PluginDatabase::remove(PluginPackage* package)
+{
+ MIMEToExtensionsMap::const_iterator it = package->mimeToExtensions().begin();
+ MIMEToExtensionsMap::const_iterator end = package->mimeToExtensions().end();
+ for ( ; it != end; ++it) {
+ PluginPackageByNameMap::iterator packageInMap = m_preferredPlugins.find(it->first);
+ if (packageInMap != m_preferredPlugins.end() && packageInMap->second == package)
+ m_preferredPlugins.remove(packageInMap);
+ }
+
+ m_plugins.remove(package);
+ m_pluginsByPath.remove(package->path());
+}
+
+void PluginDatabase::clear()
+{
+ m_plugins.clear();
+ m_pluginsByPath.clear();
+ m_pluginPathsWithTimes.clear();
+ m_registeredMIMETypes.clear();
+ m_preferredPlugins.clear();
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ m_persistentMetadataCacheIsLoaded = false;
+#endif
+}
+
+#if (!OS(WINCE)) && (!OS(SYMBIAN)) && (!OS(WINDOWS) || !ENABLE(NETSCAPE_PLUGIN_API))
+// For Safari/Win the following three methods are implemented
+// in PluginDatabaseWin.cpp, but if we can use WebCore constructs
+// for the logic we should perhaps move it here under XP_WIN?
+
+Vector<String> PluginDatabase::defaultPluginDirectories()
+{
+ Vector<String> paths;
+
+ // Add paths specific to each platform
+#if defined(XP_UNIX)
+ String userPluginPath = homeDirectoryPath();
+ userPluginPath.append(String("/.mozilla/plugins"));
+ paths.append(userPluginPath);
+
+ userPluginPath = homeDirectoryPath();
+ userPluginPath.append(String("/.netscape/plugins"));
+ paths.append(userPluginPath);
+
+ paths.append("/usr/lib/browser/plugins");
+ paths.append("/usr/local/lib/mozilla/plugins");
+ paths.append("/usr/lib/firefox/plugins");
+ paths.append("/usr/lib64/browser-plugins");
+ paths.append("/usr/lib/browser-plugins");
+ paths.append("/usr/lib/mozilla/plugins");
+ paths.append("/usr/local/netscape/plugins");
+ paths.append("/opt/mozilla/plugins");
+ paths.append("/opt/mozilla/lib/plugins");
+ paths.append("/opt/netscape/plugins");
+ paths.append("/opt/netscape/communicator/plugins");
+ paths.append("/usr/lib/netscape/plugins");
+ paths.append("/usr/lib/netscape/plugins-libc5");
+ paths.append("/usr/lib/netscape/plugins-libc6");
+ paths.append("/usr/lib64/netscape/plugins");
+ paths.append("/usr/lib64/mozilla/plugins");
+ paths.append("/usr/lib/nsbrowser/plugins");
+ paths.append("/usr/lib64/nsbrowser/plugins");
+
+ String mozHome(getenv("MOZILLA_HOME"));
+ mozHome.append("/plugins");
+ paths.append(mozHome);
+
+ Vector<String> mozPaths;
+ String mozPath(getenv("MOZ_PLUGIN_PATH"));
+ mozPath.split(UChar(':'), /* allowEmptyEntries */ false, mozPaths);
+ paths.append(mozPaths);
+#elif defined(XP_MACOSX)
+ String userPluginPath = homeDirectoryPath();
+ userPluginPath.append(String("/Library/Internet Plug-Ins"));
+ paths.append(userPluginPath);
+ paths.append("/Library/Internet Plug-Ins");
+#elif defined(XP_WIN)
+ String userPluginPath = homeDirectoryPath();
+ userPluginPath.append(String("\\Application Data\\Mozilla\\plugins"));
+ paths.append(userPluginPath);
+#endif
+
+ // Add paths specific to each port
+#if PLATFORM(QT)
+ Vector<String> qtPaths;
+ String qtPath(qgetenv("QTWEBKIT_PLUGIN_PATH").constData());
+ qtPath.split(UChar(':'), /* allowEmptyEntries */ false, qtPaths);
+ paths.append(qtPaths);
+#endif
+
+#if PLATFORM(ANDROID)
+ if (android::JavaSharedClient::GetPluginClient())
+ return android::JavaSharedClient::GetPluginClient()->getPluginDirectories();
+#endif
+
+ return paths;
+}
+
+bool PluginDatabase::isPreferredPluginDirectory(const String& path)
+{
+ String preferredPath = homeDirectoryPath();
+
+#if defined(XP_UNIX)
+ preferredPath.append(String("/.mozilla/plugins"));
+#elif defined(XP_MACOSX)
+ preferredPath.append(String("/Library/Internet Plug-Ins"));
+#elif defined(XP_WIN)
+ preferredPath.append(String("\\Application Data\\Mozilla\\plugins"));
+#endif
+
+ // TODO: We should normalize the path before doing a comparison.
+ return path == preferredPath;
+}
+
+void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const
+{
+ // FIXME: This should be a case insensitive set.
+ HashSet<String> uniqueFilenames;
+
+#if defined(XP_UNIX) || defined(ANDROID)
+ String fileNameFilter("*.so");
+#else
+ String fileNameFilter("");
+#endif
+
+ Vector<String>::const_iterator dirsEnd = m_pluginDirectories.end();
+ for (Vector<String>::const_iterator dIt = m_pluginDirectories.begin(); dIt != dirsEnd; ++dIt) {
+ Vector<String> pluginPaths = listDirectory(*dIt, fileNameFilter);
+ Vector<String>::const_iterator pluginsEnd = pluginPaths.end();
+ for (Vector<String>::const_iterator pIt = pluginPaths.begin(); pIt != pluginsEnd; ++pIt) {
+ if (!fileExists(*pIt))
+ continue;
+
+ paths.add(*pIt);
+ }
+ }
+}
+
+#endif // !OS(SYMBIAN) && !OS(WINDOWS)
+
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+
+static void fillBufferWithContentsOfFile(PlatformFileHandle file, Vector<char>& buffer)
+{
+ size_t bufferSize = 0;
+ size_t bufferCapacity = 1024;
+ buffer.resize(bufferCapacity);
+
+ do {
+ bufferSize += readFromFile(file, buffer.data() + bufferSize, bufferCapacity - bufferSize);
+ if (bufferSize == bufferCapacity) {
+ if (bufferCapacity < maximumPersistentPluginMetadataCacheSize) {
+ bufferCapacity *= 2;
+ buffer.resize(bufferCapacity);
+ } else {
+ buffer.clear();
+ return;
+ }
+ } else
+ break;
+ } while (true);
+
+ buffer.shrink(bufferSize);
+}
+
+static bool readUTF8String(String& resultString, char*& start, const char* end)
+{
+ if (start >= end)
+ return false;
+
+ int len = strlen(start);
+ resultString = String::fromUTF8(start, len);
+ start += len + 1;
+
+ return true;
+}
+
+static bool readTime(time_t& resultTime, char*& start, const char* end)
+{
+ if (start + sizeof(time_t) >= end)
+ return false;
+
+ resultTime = *reinterpret_cast_ptr<time_t*>(start);
+ start += sizeof(time_t);
+
+ return true;
+}
+
+static const char schemaVersion = '1';
+static const char persistentPluginMetadataCacheFilename[] = "PluginMetadataCache.bin";
+
+void PluginDatabase::loadPersistentMetadataCache()
+{
+ if (!isPersistentMetadataCacheEnabled() || persistentMetadataCachePath().isEmpty())
+ return;
+
+ PlatformFileHandle file;
+ String absoluteCachePath = pathByAppendingComponent(persistentMetadataCachePath(), persistentPluginMetadataCacheFilename);
+ file = openFile(absoluteCachePath, OpenForRead);
+
+ if (!isHandleValid(file))
+ return;
+
+ // Mark cache as loaded regardless of success or failure. If
+ // there's error in the cache, we won't try to load it anymore.
+ m_persistentMetadataCacheIsLoaded = true;
+
+ Vector<char> fileContents;
+ fillBufferWithContentsOfFile(file, fileContents);
+ closeFile(file);
+
+ if (fileContents.size() < 2 || fileContents.first() != schemaVersion || fileContents.last() != '\0') {
+ LOG_ERROR("Unable to read plugin metadata cache: corrupt schema");
+ deleteFile(absoluteCachePath);
+ return;
+ }
+
+ char* bufferPos = fileContents.data() + 1;
+ char* end = fileContents.data() + fileContents.size();
+
+ PluginSet cachedPlugins;
+ HashMap<String, time_t> cachedPluginPathsWithTimes;
+ HashMap<String, RefPtr<PluginPackage> > cachedPluginsByPath;
+
+ while (bufferPos < end) {
+ String path;
+ time_t lastModified;
+ String name;
+ String desc;
+ String mimeDesc;
+ if (!(readUTF8String(path, bufferPos, end)
+ && readTime(lastModified, bufferPos, end)
+ && readUTF8String(name, bufferPos, end)
+ && readUTF8String(desc, bufferPos, end)
+ && readUTF8String(mimeDesc, bufferPos, end))) {
+ LOG_ERROR("Unable to read plugin metadata cache: corrupt data");
+ deleteFile(absoluteCachePath);
+ return;
+ }
+
+ // Skip metadata that points to plugins from directories that
+ // are not part of plugin directory list anymore.
+ String pluginDirectoryName = directoryName(path);
+ if (m_pluginDirectories.find(pluginDirectoryName) == WTF::notFound)
+ continue;
+
+ RefPtr<PluginPackage> package = PluginPackage::createPackageFromCache(path, lastModified, name, desc, mimeDesc);
+
+ if (package && cachedPlugins.add(package).second) {
+ cachedPluginPathsWithTimes.add(package->path(), package->lastModified());
+ cachedPluginsByPath.add(package->path(), package);
+ }
+ }
+
+ m_plugins.swap(cachedPlugins);
+ m_pluginsByPath.swap(cachedPluginsByPath);
+ m_pluginPathsWithTimes.swap(cachedPluginPathsWithTimes);
+}
+
+static bool writeUTF8String(PlatformFileHandle file, const String& string)
+{
+ CString utf8String = string.utf8();
+ int length = utf8String.length() + 1;
+ return writeToFile(file, utf8String.data(), length) == length;
+}
+
+static bool writeTime(PlatformFileHandle file, const time_t& time)
+{
+ return writeToFile(file, reinterpret_cast<const char*>(&time), sizeof(time_t)) == sizeof(time_t);
+}
+
+void PluginDatabase::updatePersistentMetadataCache()
+{
+ if (!isPersistentMetadataCacheEnabled() || persistentMetadataCachePath().isEmpty())
+ return;
+
+ makeAllDirectories(persistentMetadataCachePath());
+ String absoluteCachePath = pathByAppendingComponent(persistentMetadataCachePath(), persistentPluginMetadataCacheFilename);
+ deleteFile(absoluteCachePath);
+
+ if (m_plugins.isEmpty())
+ return;
+
+ PlatformFileHandle file;
+ file = openFile(absoluteCachePath, OpenForWrite);
+
+ if (!isHandleValid(file)) {
+ LOG_ERROR("Unable to open plugin metadata cache for saving");
+ return;
+ }
+
+ char localSchemaVersion = schemaVersion;
+ if (writeToFile(file, &localSchemaVersion, 1) != 1) {
+ LOG_ERROR("Unable to write plugin metadata cache schema");
+ closeFile(file);
+ deleteFile(absoluteCachePath);
+ return;
+ }
+
+ PluginSet::const_iterator end = m_plugins.end();
+ for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
+ if (!(writeUTF8String(file, (*it)->path())
+ && writeTime(file, (*it)->lastModified())
+ && writeUTF8String(file, (*it)->name())
+ && writeUTF8String(file, (*it)->description())
+ && writeUTF8String(file, (*it)->fullMIMEDescription()))) {
+ LOG_ERROR("Unable to write plugin metadata to cache");
+ closeFile(file);
+ deleteFile(absoluteCachePath);
+ return;
+ }
+ }
+
+ closeFile(file);
+}
+
+bool PluginDatabase::isPersistentMetadataCacheEnabled()
+{
+ return gPersistentPluginMetadataCacheIsEnabled;
+}
+
+void PluginDatabase::setPersistentMetadataCacheEnabled(bool isEnabled)
+{
+ gPersistentPluginMetadataCacheIsEnabled = isEnabled;
+}
+
+String PluginDatabase::persistentMetadataCachePath()
+{
+ return WebCore::persistentPluginMetadataCachePath();
+}
+
+void PluginDatabase::setPersistentMetadataCachePath(const String& persistentMetadataCachePath)
+{
+ WebCore::persistentPluginMetadataCachePath() = persistentMetadataCachePath;
+}
+#endif
+}
diff --git a/Source/WebCore/plugins/PluginDatabase.h b/Source/WebCore/plugins/PluginDatabase.h
new file mode 100644
index 0000000..b1e1525
--- /dev/null
+++ b/Source/WebCore/plugins/PluginDatabase.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginDatabase_h
+#define PluginDatabase_h
+
+#include "PlatformString.h"
+#include "PluginPackage.h"
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+#if defined(ANDROID_PLUGINS)
+namespace android {
+ class WebSettings;
+}
+#endif
+
+namespace WebCore {
+ class Element;
+ class Frame;
+ class IntSize;
+ class KURL;
+ class PluginDatabaseClient;
+ class PluginPackage;
+
+ typedef HashSet<RefPtr<PluginPackage>, PluginPackageHash> PluginSet;
+
+ class PluginDatabase : public Noncopyable {
+ public:
+ PluginDatabase();
+
+ // The first call to installedPlugins creates the plugin database
+ // and by default populates it with the plugins installed on the system.
+ // For testing purposes, it is possible to not populate the database
+ // automatically, as the plugins might affect the DRT results by
+ // writing to a.o. stderr.
+ static PluginDatabase* installedPlugins(bool populate = true);
+
+ bool refresh();
+ void clear();
+ Vector<PluginPackage*> plugins() const;
+ bool isMIMETypeRegistered(const String& mimeType);
+ void addExtraPluginDirectory(const String&);
+
+ static bool isPreferredPluginDirectory(const String& directory);
+ static int preferredPluginCompare(const void*, const void*);
+
+ PluginPackage* findPlugin(const KURL&, String& mimeType);
+ PluginPackage* pluginForMIMEType(const String& mimeType);
+ void setPreferredPluginForMIMEType(const String& mimeType, PluginPackage* plugin);
+
+ void setPluginDirectories(const Vector<String>& directories)
+ {
+ clear();
+ m_pluginDirectories = directories;
+ }
+
+ static Vector<String> defaultPluginDirectories();
+ Vector<String> pluginDirectories() const { return m_pluginDirectories; }
+
+ String MIMETypeForExtension(const String& extension) const;
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ static bool isPersistentMetadataCacheEnabled();
+ static void setPersistentMetadataCacheEnabled(bool isEnabled);
+ static String persistentMetadataCachePath();
+ static void setPersistentMetadataCachePath(const String& persistentMetadataCachePath);
+#endif
+
+ private:
+ void getPluginPathsInDirectories(HashSet<String>&) const;
+ void getDeletedPlugins(PluginSet&) const;
+
+ // Returns whether the plugin was actually added or not (it won't be added if it's a duplicate of an existing plugin).
+ bool add(PassRefPtr<PluginPackage>);
+ void remove(PluginPackage*);
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ void loadPersistentMetadataCache();
+ void updatePersistentMetadataCache();
+#endif
+
+ Vector<String> m_pluginDirectories;
+ HashSet<String> m_registeredMIMETypes;
+ PluginSet m_plugins;
+ HashMap<String, RefPtr<PluginPackage> > m_pluginsByPath;
+ HashMap<String, time_t> m_pluginPathsWithTimes;
+
+#if defined(ANDROID_PLUGINS)
+ // Need access to setPluginDirectories() to change the default
+ // path after startup.
+ friend class ::android::WebSettings;
+#endif
+ HashMap<String, RefPtr<PluginPackage> > m_preferredPlugins;
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ bool m_persistentMetadataCacheIsLoaded;
+#endif
+ };
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/plugins/PluginDebug.cpp b/Source/WebCore/plugins/PluginDebug.cpp
new file mode 100644
index 0000000..8c3efcb
--- /dev/null
+++ b/Source/WebCore/plugins/PluginDebug.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 "PluginDebug.h"
+#include "PlatformString.h"
+
+#if !LOG_DISABLED
+
+namespace WebCore {
+
+static const char* const errorStrings[] = {
+ "No errors occurred.", /* NPERR_NO_ERROR */
+ "Error with no specific error code occurred.", /* NPERR_GENERIC_ERROR */
+ "Invalid instance passed to the plug-in.", /* NPERR_INVALID_INSTANCE_ERROR */
+ "Function table invalid.", /* NPERR_INVALID_FUNCTABLE_ERROR */
+ "Loading of plug-in failed.", /* NPERR_MODULE_LOAD_FAILED_ERROR */
+ "Memory allocation failed.", /* NPERR_OUT_OF_MEMORY_ERROR */
+ "Plug-in missing or invalid.", /* NPERR_INVALID_PLUGIN_ERROR */
+ "Plug-in directory missing or invalid.", /* NPERR_INVALID_PLUGIN_DIR_ERROR */
+ "Versions of plug-in and Communicator do not match.", /* NPERR_INCOMPATIBLE_VERSION_ERROR */
+ "Parameter missing or invalid.", /* NPERR_INVALID_PARAM */
+ "URL missing or invalid.", /* NPERR_INVALID_URL */
+ "File missing or invalid.", /* NPERR_FILE_NOT_FOUND */
+ "Stream contains no data.", /* NPERR_NO_DATA */
+ "Seekable stream expected.", /* NPERR_STREAM_NOT_SEEKABLE */
+ "Unknown error code"
+};
+
+#ifdef XP_MACOSX
+static const char* const drawingModels[] = {
+ "NPDrawingModelQuickDraw",
+ "NPDrawingModelCoreGraphics",
+ "NPDrawingModelOpenGL",
+ "NPDrawingModelCoreAnimation"
+};
+
+static const char* const eventModels[] = {
+ "NPEventModelCarbon",
+ "NPEventModelCocoa"
+};
+#endif //XP_MACOSX
+
+const char* prettyNameForNPError(NPError error)
+{
+ return errorStrings[error];
+}
+
+#ifdef XP_MACOSX
+const char* prettyNameForDrawingModel(NPDrawingModel drawingModel)
+{
+ return drawingModels[drawingModel];
+}
+
+const char* prettyNameForEventModel(NPEventModel eventModel)
+{
+ return eventModels[eventModel];
+}
+#endif //XP_MACOSX
+
+CString prettyNameForNPNVariable(NPNVariable variable)
+{
+ switch (variable) {
+ case NPNVxDisplay: return "NPNVxDisplay";
+ case NPNVxtAppContext: return "NPNVxtAppContext";
+ case NPNVnetscapeWindow: return "NPNVnetscapeWindow";
+ case NPNVjavascriptEnabledBool: return "NPNVjavascriptEnabledBool";
+ case NPNVasdEnabledBool: return "NPNVasdEnabledBool";
+ case NPNVisOfflineBool: return "NPNVisOfflineBool";
+
+ case NPNVserviceManager: return "NPNVserviceManager (not supported)";
+ case NPNVDOMElement: return "NPNVDOMElement (not supported)";
+ case NPNVDOMWindow: return "NPNVDOMWindow (not supported)";
+ case NPNVToolkit: return "NPNVToolkit (not supported)";
+ case NPNVSupportsXEmbedBool: return "NPNVSupportsXEmbedBool (not supported)";
+
+ case NPNVWindowNPObject: return "NPNVWindowNPObject";
+ case NPNVPluginElementNPObject: return "NPNVPluginElementNPObject";
+ case NPNVSupportsWindowless: return "NPNVSupportsWindowless";
+ case NPNVprivateModeBool: return "NPNVprivateModeBool";
+
+#ifdef XP_MACOSX
+ case NPNVpluginDrawingModel: return "NPNVpluginDrawingModel";
+#ifndef NP_NO_QUICKDRAW
+ case NPNVsupportsQuickDrawBool: return "NPNVsupportsQuickDrawBool";
+#endif
+ case NPNVsupportsCoreGraphicsBool: return "NPNVsupportsCoreGraphicsBool";
+ case NPNVsupportsOpenGLBool: return "NPNVsupportsOpenGLBool";
+ case NPNVsupportsCoreAnimationBool: return "NPNVsupportsCoreAnimationBool";
+#ifndef NP_NO_CARBON
+ case NPNVsupportsCarbonBool: return "NPNVsupportsCarbonBool";
+#endif
+ case NPNVsupportsCocoaBool: return "NPNVsupportsCocoaBool";
+#endif
+
+ default: return "Unknown variable";
+ }
+}
+
+CString prettyNameForNPPVariable(NPPVariable variable, void* value)
+{
+ switch (variable) {
+ case NPPVpluginNameString: return "NPPVpluginNameString";
+ case NPPVpluginDescriptionString: return "NPPVpluginDescriptionString";
+ case NPPVpluginWindowBool: return "NPPVpluginWindowBool";
+ case NPPVpluginTransparentBool: return "NPPVpluginTransparentBool";
+
+ case NPPVjavaClass: return "NPPVjavaClass (not supported)";
+ case NPPVpluginWindowSize: return "NPPVpluginWindowSize (not supported)";
+ case NPPVpluginTimerInterval: return "NPPVpluginTimerInterval (not supported)";
+ case NPPVpluginScriptableInstance: return "NPPVpluginScriptableInstance (not supported)";
+ case NPPVpluginScriptableIID: return "NPPVpluginScriptableIID (not supported)";
+ case NPPVjavascriptPushCallerBool: return "NPPVjavascriptPushCallerBool (not supported)";
+ case NPPVpluginKeepLibraryInMemory: return "NPPVpluginKeepLibraryInMemory (not supported)";
+ case NPPVpluginNeedsXEmbed: return "NPPVpluginNeedsXEmbed (not supported)";
+
+ case NPPVpluginScriptableNPObject: return "NPPVpluginScriptableNPObject";
+
+ case NPPVformValue: return "NPPVformValue (not supported)";
+ case NPPVpluginUrlRequestsDisplayedBool: return "NPPVpluginUrlRequestsDisplayedBool (not supported)";
+
+ case NPPVpluginWantsAllNetworkStreams: return "NPPVpluginWantsAllNetworkStreams";
+ case NPPVpluginCancelSrcStream: return "NPPVpluginCancelSrcStream";
+
+#ifdef XP_MACOSX
+ case NPPVpluginDrawingModel: {
+ String result("NPPVpluginDrawingModel, ");
+ result.append(prettyNameForDrawingModel(NPDrawingModel(uintptr_t(value))));
+ return result.latin1();
+ }
+ case NPPVpluginEventModel: {
+ String result("NPPVpluginEventModel, ");
+ result.append(prettyNameForEventModel(NPEventModel(uintptr_t(value))));
+ return result.latin1();
+ }
+ case NPPVpluginCoreAnimationLayer: return "NPPVpluginCoreAnimationLayer";
+#endif
+
+ default: return "Unknown variable";
+ }
+}
+
+CString prettyNameForNPNURLVariable(NPNURLVariable variable)
+{
+ switch (variable) {
+ case NPNURLVCookie: return "NPNURLVCookie";
+ case NPNURLVProxy: return "NPNURLVProxy";
+ default: return "Unknown variable";
+ }
+}
+} // namespace WebCore
+
+#endif // !LOG_DISABLED
diff --git a/Source/WebCore/plugins/PluginDebug.h b/Source/WebCore/plugins/PluginDebug.h
new file mode 100644
index 0000000..017e686
--- /dev/null
+++ b/Source/WebCore/plugins/PluginDebug.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginDebug_h
+#define PluginDebug_h
+
+#include "Logging.h"
+#include "npruntime_internal.h"
+#include <wtf/text/CString.h>
+
+#define LOG_NPERROR(err) if (err != NPERR_NO_ERROR) LOG_VERBOSE(Plugins, "%s\n", prettyNameForNPError(err))
+#define LOG_PLUGIN_NET_ERROR() LOG_VERBOSE(Plugins, "Stream failed due to problems with network, disk I/O, lack of memory, or other problems.\n")
+
+#if !LOG_DISABLED
+
+namespace WebCore {
+
+const char* prettyNameForNPError(NPError error);
+
+CString prettyNameForNPNVariable(NPNVariable variable);
+CString prettyNameForNPPVariable(NPPVariable variable, void* value);
+CString prettyNameForNPNURLVariable(NPNURLVariable variable);
+
+#ifdef XP_MACOSX
+const char* prettyNameForDrawingModel(NPDrawingModel drawingModel);
+const char* prettyNameForEventModel(NPEventModel eventModel);
+#endif
+
+} // namespace WebCore
+
+#endif // !LOG_DISABLED
+
+#endif // PluginDebug_h
diff --git a/Source/WebCore/plugins/PluginMainThreadScheduler.cpp b/Source/WebCore/plugins/PluginMainThreadScheduler.cpp
new file mode 100644
index 0000000..7528676
--- /dev/null
+++ b/Source/WebCore/plugins/PluginMainThreadScheduler.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 "PluginMainThreadScheduler.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+PluginMainThreadScheduler& PluginMainThreadScheduler::scheduler()
+{
+ DEFINE_STATIC_LOCAL(PluginMainThreadScheduler, scheduler, ());
+
+ return scheduler;
+}
+
+PluginMainThreadScheduler::PluginMainThreadScheduler()
+ : m_callPending(false)
+{
+}
+
+void PluginMainThreadScheduler::scheduleCall(NPP npp, MainThreadFunction function, void* userData)
+{
+ MutexLocker lock(m_queueMutex);
+
+ CallQueueMap::iterator it = m_callQueueMap.find(npp);
+ if (it == m_callQueueMap.end())
+ return;
+
+ it->second.append(Call(function, userData));
+
+ if (!m_callPending) {
+ callOnMainThread(mainThreadCallback, this);
+ m_callPending = true;
+ }
+}
+
+void PluginMainThreadScheduler::registerPlugin(NPP npp)
+{
+ MutexLocker lock(m_queueMutex);
+
+ ASSERT(!m_callQueueMap.contains(npp));
+ m_callQueueMap.set(npp, Deque<Call>());
+}
+
+void PluginMainThreadScheduler::unregisterPlugin(NPP npp)
+{
+ MutexLocker lock(m_queueMutex);
+
+ ASSERT(m_callQueueMap.contains(npp));
+ m_callQueueMap.remove(npp);
+}
+
+void PluginMainThreadScheduler::dispatchCallsForPlugin(NPP npp, const Deque<Call>& calls)
+{
+ Deque<Call>::const_iterator end = calls.end();
+ for (Deque<Call>::const_iterator it = calls.begin(); it != end; ++it) {
+ // Check if the plug-in has been destroyed.
+ {
+ MutexLocker lock(m_queueMutex);
+ if (!m_callQueueMap.contains(npp))
+ return;
+ }
+
+ (*it).performCall();
+ }
+}
+
+void PluginMainThreadScheduler::dispatchCalls()
+{
+ m_queueMutex.lock();
+ CallQueueMap copy(m_callQueueMap);
+
+ {
+ // Empty all the queues in the original map
+ CallQueueMap::iterator end = m_callQueueMap.end();
+ for (CallQueueMap::iterator it = m_callQueueMap.begin(); it != end; ++it)
+ it->second.clear();
+ }
+
+ m_callPending = false;
+ m_queueMutex.unlock();
+
+ CallQueueMap::iterator end = copy.end();
+ for (CallQueueMap::iterator it = copy.begin(); it != end; ++it)
+ dispatchCallsForPlugin(it->first, it->second);
+}
+
+void PluginMainThreadScheduler::mainThreadCallback(void* context)
+{
+ static_cast<PluginMainThreadScheduler*>(context)->dispatchCalls();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/PluginMainThreadScheduler.h b/Source/WebCore/plugins/PluginMainThreadScheduler.h
new file mode 100644
index 0000000..610e89c
--- /dev/null
+++ b/Source/WebCore/plugins/PluginMainThreadScheduler.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 PluginMainThreadScheduler_h
+#define PluginMainThreadScheduler_h
+
+#include <wtf/Deque.h>
+#include <wtf/HashMap.h>
+#include <wtf/MainThread.h>
+#include <wtf/Threading.h>
+
+typedef struct _NPP NPP_t;
+typedef NPP_t* NPP;
+
+namespace WebCore {
+
+class PluginMainThreadScheduler : public Noncopyable {
+public:
+ typedef void MainThreadFunction(void*);
+
+ static PluginMainThreadScheduler& scheduler();
+
+ void scheduleCall(NPP, MainThreadFunction*, void* userData);
+
+ void registerPlugin(NPP);
+ void unregisterPlugin(NPP);
+
+private:
+ PluginMainThreadScheduler();
+ void dispatchCalls();
+
+ class Call;
+
+ void dispatchCallsForPlugin(NPP, const Deque<Call>& calls);
+ typedef HashMap<NPP, Deque<Call> > CallQueueMap;
+
+ static void mainThreadCallback(void* context);
+
+ class Call {
+ public:
+ Call(MainThreadFunction* function, void* userData)
+ : m_function(function)
+ , m_userData(userData)
+ {
+ }
+
+ void performCall() const
+ {
+ m_function(m_userData);
+ }
+
+ private:
+ MainThreadFunction* m_function;
+ void* m_userData;
+ };
+
+ bool m_callPending;
+ CallQueueMap m_callQueueMap;
+ Mutex m_queueMutex;
+};
+
+} // namespace WebCore
+
+#endif // PluginMainThreadScheduler_h
diff --git a/Source/WebCore/plugins/PluginPackage.cpp b/Source/WebCore/plugins/PluginPackage.cpp
new file mode 100644
index 0000000..10149bf
--- /dev/null
+++ b/Source/WebCore/plugins/PluginPackage.cpp
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ *
+ * 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>
+
+namespace WebCore {
+
+PluginPackage::~PluginPackage()
+{
+ // This destructor gets called during refresh() if PluginDatabase's
+ // PluginSet hash is already populated, as it removes items from
+ // the hash table. Calling the destructor on a loaded plug-in of
+ // course would cause a crash, so we check to call unload before we
+ // ASSERT.
+ // FIXME: There is probably a better way to fix this.
+ if (!m_loadCount)
+ unloadWithoutShutdown();
+ else
+ unload();
+
+ ASSERT(!m_isLoaded);
+}
+
+void PluginPackage::freeLibrarySoon()
+{
+ ASSERT(!m_freeLibraryTimer.isActive());
+ ASSERT(m_module);
+ ASSERT(!m_loadCount);
+
+ m_freeLibraryTimer.startOneShot(0);
+}
+
+void PluginPackage::freeLibraryTimerFired(Timer<PluginPackage>*)
+{
+ ASSERT(m_module);
+ ASSERT(!m_loadCount);
+
+ unloadModule(m_module);
+ m_module = 0;
+}
+
+
+int PluginPackage::compare(const PluginPackage& compareTo) const
+{
+ // Sort plug-ins that allow multiple instances first.
+ bool AallowsMultipleInstances = !quirks().contains(PluginQuirkDontAllowMultipleInstances);
+ bool BallowsMultipleInstances = !compareTo.quirks().contains(PluginQuirkDontAllowMultipleInstances);
+ if (AallowsMultipleInstances != BallowsMultipleInstances)
+ return AallowsMultipleInstances ? -1 : 1;
+
+ // Sort plug-ins in a preferred path first.
+ bool AisInPreferredDirectory = PluginDatabase::isPreferredPluginDirectory(parentDirectory());
+ bool BisInPreferredDirectory = PluginDatabase::isPreferredPluginDirectory(compareTo.parentDirectory());
+ if (AisInPreferredDirectory != BisInPreferredDirectory)
+ return AisInPreferredDirectory ? -1 : 1;
+
+ int diff = strcmp(name().utf8().data(), compareTo.name().utf8().data());
+ if (diff)
+ return diff;
+
+ diff = compareFileVersion(compareTo.version());
+ if (diff)
+ return diff;
+
+ return strcmp(parentDirectory().utf8().data(), compareTo.parentDirectory().utf8().data());
+}
+
+PluginPackage::PluginPackage(const String& path, const time_t& lastModified)
+ : m_isEnabled(true)
+ , m_isLoaded(false)
+ , m_loadCount(0)
+ , m_path(path)
+ , m_moduleVersion(0)
+ , m_module(0)
+ , m_lastModified(lastModified)
+ , m_freeLibraryTimer(this, &PluginPackage::freeLibraryTimerFired)
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ , m_infoIsFromCache(true)
+#endif
+{
+ m_fileName = pathGetFileName(m_path);
+ m_parentDirectory = m_path.left(m_path.length() - m_fileName.length() - 1);
+}
+
+#if !OS(SYMBIAN)
+void PluginPackage::unload()
+{
+ if (!m_isLoaded)
+ return;
+
+ if (--m_loadCount > 0)
+ return;
+
+ m_NPP_Shutdown();
+
+ unloadWithoutShutdown();
+}
+#endif // !OS(SYMBIAN)
+
+void PluginPackage::unloadWithoutShutdown()
+{
+ if (!m_isLoaded)
+ return;
+
+ ASSERT(!m_loadCount);
+ ASSERT(m_module);
+
+ // <rdar://5530519>: Crash when closing tab with pdf file (Reader 7 only)
+ // If the plugin has subclassed its parent window, as with Reader 7, we may have
+ // gotten here by way of the plugin's internal window proc forwarding a message to our
+ // original window proc. If we free the plugin library from here, we will jump back
+ // to code we just freed when we return, so delay calling FreeLibrary at least until
+ // the next message loop
+ freeLibrarySoon();
+
+ m_isLoaded = false;
+}
+
+void PluginPackage::setEnabled(bool enabled)
+{
+ m_isEnabled = enabled;
+}
+
+PassRefPtr<PluginPackage> PluginPackage::createPackage(const String& path, const time_t& lastModified)
+{
+ RefPtr<PluginPackage> package = adoptRef(new PluginPackage(path, lastModified));
+
+ if (!package->fetchInfo())
+ return 0;
+
+ return package.release();
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+PassRefPtr<PluginPackage> PluginPackage::createPackageFromCache(const String& path, const time_t& lastModified, const String& name, const String& description, const String& mimeDescription)
+{
+ RefPtr<PluginPackage> package = adoptRef(new PluginPackage(path, lastModified));
+ package->m_name = name;
+ package->m_description = description;
+ package->determineModuleVersionFromDescription();
+ package->setMIMEDescription(mimeDescription);
+ package->m_infoIsFromCache = true;
+ return package.release();
+}
+#endif
+
+#if defined(XP_UNIX)
+void PluginPackage::determineQuirks(const String& mimeType)
+{
+ 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);
+ return;
+ }
+
+ if (mimeType == "application/x-shockwave-flash") {
+ static const PlatformModuleVersion flashTenVersion(0x0a000000);
+
+ if (compareFileVersion(flashTenVersion) >= 0) {
+ // Flash 10.0 b218 doesn't like having a NULL window handle
+ m_quirks.add(PluginQuirkDontSetNullWindowHandleOnDestroy);
+#if PLATFORM(QT)
+ m_quirks.add(PluginQuirkRequiresGtkToolKit);
+#endif
+ } else {
+ // Flash 9 and older requests windowless plugins if we return a mozilla user agent
+ m_quirks.add(PluginQuirkWantsMozillaUserAgent);
+ }
+
+#if PLATFORM(QT)
+ // Flash will crash on repeated calls to SetWindow in windowed mode
+ m_quirks.add(PluginQuirkDontCallSetWindowMoreThanOnce);
+
+#if CPU(X86_64)
+ // 64-bit Flash freezes if right-click is sent in windowless mode
+ m_quirks.add(PluginQuirkIgnoreRightClickInWindowlessMode);
+#endif
+#endif
+
+ m_quirks.add(PluginQuirkRequiresDefaultScreenDepth);
+ m_quirks.add(PluginQuirkThrottleInvalidate);
+ m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages);
+ m_quirks.add(PluginQuirkFlashURLNotifyBug);
+ }
+
+#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
+ // Passing a 32-bit depth pixmap to NPAPI plugins is too inefficient. Instead, pass a X Pixmap
+ // that has same depth as the screen depth since graphics operations are optimized
+ // for this depth.
+ m_quirks.add(PluginQuirkRequiresDefaultScreenDepth);
+#endif
+}
+#endif
+
+#if !OS(WINDOWS)
+void PluginPackage::determineModuleVersionFromDescription()
+{
+ // It's a bit lame to detect the plugin version by parsing it
+ // from the plugin description string, but it doesn't seem that
+ // version information is available in any standardized way at
+ // the module level, like in Windows
+
+ if (m_description.isEmpty())
+ return;
+
+ if (m_description.startsWith("Shockwave Flash") && m_description.length() >= 19) {
+ // The flash version as a PlatformModuleVersion differs on Unix from Windows
+ // since the revision can be larger than a 8 bits, so we allow it 16 here and
+ // push the major/minor up 8 bits. Thus on Unix, Flash's version may be
+ // 0x0a000000 instead of 0x000a0000.
+
+ Vector<String> versionParts;
+ m_description.substring(16).split(' ', /*allowEmptyEntries =*/ false, versionParts);
+ if (versionParts.isEmpty())
+ return;
+
+ if (versionParts.size() >= 1) {
+ Vector<String> majorMinorParts;
+ versionParts[0].split('.', majorMinorParts);
+ if (majorMinorParts.size() >= 1) {
+ bool converted = false;
+ unsigned major = majorMinorParts[0].toUInt(&converted);
+ if (converted)
+ m_moduleVersion = (major & 0xff) << 24;
+ }
+ if (majorMinorParts.size() == 2) {
+ bool converted = false;
+ unsigned minor = majorMinorParts[1].toUInt(&converted);
+ if (converted)
+ m_moduleVersion |= (minor & 0xff) << 16;
+ }
+ }
+
+ if (versionParts.size() >= 2) {
+ String revision = versionParts[1];
+ if (revision.length() > 1 && (revision[0] == 'r' || revision[0] == 'b')) {
+ revision.remove(0, 1);
+ m_moduleVersion |= revision.toInt() & 0xffff;
+ }
+ }
+ }
+}
+#endif
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+void PluginPackage::initializeBrowserFuncs()
+{
+ memset(&m_browserFuncs, 0, sizeof(m_browserFuncs));
+ m_browserFuncs.size = sizeof(m_browserFuncs);
+ m_browserFuncs.version = NPVersion();
+
+ 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;
+ m_browserFuncs.getvalueforurl = NPN_GetValueForURL;
+ m_browserFuncs.setvalueforurl = NPN_SetValueForURL;
+ m_browserFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo;
+}
+#endif
+
+#if ENABLE(PLUGIN_PACKAGE_SIMPLE_HASH)
+unsigned PluginPackage::hash() const
+{
+ unsigned hashCodes[] = {
+ m_path.impl()->hash(),
+ m_lastModified
+ };
+
+ return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+}
+
+bool PluginPackage::equal(const PluginPackage& a, const PluginPackage& b)
+{
+ return a.m_description == b.m_description;
+}
+#endif
+
+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 OS(WINDOWS)
+ 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;
+#else
+ if (m_moduleVersion != compareVersion)
+ return m_moduleVersion > compareVersion ? 1 : -1;
+#endif
+
+ return 0;
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+bool PluginPackage::ensurePluginLoaded()
+{
+ if (!m_infoIsFromCache)
+ return m_isLoaded;
+
+ m_quirks = PluginQuirkSet();
+ m_name = String();
+ m_description = String();
+ m_fullMIMEDescription = String();
+ m_moduleVersion = 0;
+
+ return fetchInfo();
+}
+#endif
+
+}
diff --git a/Source/WebCore/plugins/PluginPackage.h b/Source/WebCore/plugins/PluginPackage.h
new file mode 100644
index 0000000..f4d1dac
--- /dev/null
+++ b/Source/WebCore/plugins/PluginPackage.h
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+#ifndef PluginPackage_h
+#define PluginPackage_h
+
+#include "FileSystem.h"
+#include "PlatformString.h"
+#include "PluginQuirkSet.h"
+#include "Timer.h"
+#include "npruntime_internal.h"
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/StringHash.h>
+
+#if OS(SYMBIAN)
+class QPluginLoader;
+class NPInterface;
+#endif
+
+namespace WebCore {
+ typedef HashMap<String, String> MIMEToDescriptionsMap;
+ typedef HashMap<String, Vector<String> > MIMEToExtensionsMap;
+
+ class PluginPackage : public RefCounted<PluginPackage> {
+ public:
+ ~PluginPackage();
+ static PassRefPtr<PluginPackage> createPackage(const String& path, const time_t& lastModified);
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ static PassRefPtr<PluginPackage> createPackageFromCache(const String& path, const time_t& lastModified, const String& name, const String& description, const String& mimeDescription);
+#endif
+
+ const String& name() const { return m_name; }
+ const String& description() const { return m_description; }
+ const String& path() const { return m_path; }
+ const String& fileName() const { return m_fileName; }
+ const String& parentDirectory() const { return m_parentDirectory; }
+ uint16_t NPVersion() const;
+ time_t lastModified() const { return m_lastModified; }
+
+ const MIMEToDescriptionsMap& mimeToDescriptions() const { return m_mimeToDescriptions; }
+ const MIMEToExtensionsMap& mimeToExtensions() const { return m_mimeToExtensions; }
+
+ unsigned hash() const;
+ static bool equal(const PluginPackage& a, const PluginPackage& b);
+
+ bool load();
+ void unload();
+ void unloadWithoutShutdown();
+
+ bool isEnabled() const { return m_isEnabled; }
+ void setEnabled(bool);
+
+ const NPPluginFuncs* pluginFuncs() const { return &m_pluginFuncs; }
+ int compareFileVersion(const PlatformModuleVersion&) const;
+ int compare(const PluginPackage&) const;
+ PluginQuirkSet quirks() const { return m_quirks; }
+ const PlatformModuleVersion& version() const { return m_moduleVersion; }
+#if OS(SYMBIAN)
+ NPInterface* npInterface() const { return m_npInterface; }
+#endif // OS(SYMBIAN)
+
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ bool ensurePluginLoaded();
+ void setMIMEDescription(const String& mimeDescription);
+ String fullMIMEDescription() const { return m_fullMIMEDescription;}
+#endif
+ private:
+ PluginPackage(const String& path, const time_t& lastModified);
+
+#if OS(SYMBIAN)
+ NPInterface* m_npInterface;
+ QPluginLoader* m_pluginLoader;
+#endif // OS(SYMBIAN)
+ bool fetchInfo();
+ bool isPluginBlacklisted();
+ void determineQuirks(const String& mimeType);
+
+ void determineModuleVersionFromDescription();
+ void initializeBrowserFuncs();
+
+ bool m_isEnabled;
+ bool m_isLoaded;
+ int m_loadCount;
+
+ String m_description;
+ String m_path;
+ String m_fileName;
+ String m_name;
+ String m_parentDirectory;
+
+ PlatformModuleVersion m_moduleVersion;
+
+ MIMEToDescriptionsMap m_mimeToDescriptions;
+ MIMEToExtensionsMap m_mimeToExtensions;
+
+ PlatformModule m_module;
+ time_t m_lastModified;
+
+ NPP_ShutdownProcPtr m_NPP_Shutdown;
+ NPPluginFuncs m_pluginFuncs;
+ NPNetscapeFuncs m_browserFuncs;
+
+ void freeLibrarySoon();
+ void freeLibraryTimerFired(Timer<PluginPackage>*);
+ Timer<PluginPackage> m_freeLibraryTimer;
+
+ PluginQuirkSet m_quirks;
+#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
+ String m_fullMIMEDescription;
+ bool m_infoIsFromCache;
+#endif
+ };
+
+ struct PluginPackageHash {
+ static unsigned hash(const uintptr_t key) { return reinterpret_cast<PluginPackage*>(key)->hash(); }
+ static unsigned hash(const RefPtr<PluginPackage>& key) { return key->hash(); }
+
+ static bool equal(const uintptr_t a, const uintptr_t b) { return equal(reinterpret_cast<PluginPackage*>(a), reinterpret_cast<PluginPackage*>(b)); }
+ static bool equal(const RefPtr<PluginPackage>& a, const RefPtr<PluginPackage>& b) { return PluginPackage::equal(*a.get(), *b.get()); }
+ static const bool safeToCompareToEmptyOrDeleted = false;
+ };
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/plugins/PluginPackageNone.cpp b/Source/WebCore/plugins/PluginPackageNone.cpp
new file mode 100644
index 0000000..f7e2a6b
--- /dev/null
+++ b/Source/WebCore/plugins/PluginPackageNone.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> 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 "PluginPackage.h"
+
+namespace WebCore {
+
+void PluginPackage::determineQuirks(const String&)
+{
+}
+
+bool PluginPackage::fetchInfo()
+{
+ return false;
+}
+
+bool PluginPackage::load()
+{
+ return false;
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+uint16_t PluginPackage::NPVersion() const
+{
+ return 0;
+}
+#endif
+
+}
diff --git a/Source/WebCore/plugins/PluginQuirkSet.h b/Source/WebCore/plugins/PluginQuirkSet.h
new file mode 100644
index 0000000..1a684fe
--- /dev/null
+++ b/Source/WebCore/plugins/PluginQuirkSet.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginQuirkSet_h
+#define PluginQuirkSet_h
+
+
+namespace WebCore {
+
+ enum PluginQuirk {
+ PluginQuirkWantsMozillaUserAgent = 1 << 0,
+ PluginQuirkDeferFirstSetWindowCall = 1 << 1,
+ PluginQuirkThrottleInvalidate = 1 << 2,
+ PluginQuirkRemoveWindowlessVideoParam = 1 << 3,
+ PluginQuirkThrottleWMUserPlusOneMessages = 1 << 4,
+ PluginQuirkDontUnloadPlugin = 1 << 5,
+ PluginQuirkDontCallWndProcForSameMessageRecursively = 1 << 6,
+ PluginQuirkHasModalMessageLoop = 1 << 7,
+ PluginQuirkFlashURLNotifyBug = 1 << 8,
+ PluginQuirkDontClipToZeroRectWhenScrolling = 1 << 9,
+ PluginQuirkDontSetNullWindowHandleOnDestroy = 1 << 10,
+ PluginQuirkDontAllowMultipleInstances = 1 << 11,
+ PluginQuirkRequiresGtkToolKit = 1 << 12,
+ PluginQuirkRequiresDefaultScreenDepth = 1 << 13,
+ PluginQuirkDontCallSetWindowMoreThanOnce = 1 << 14,
+ PluginQuirkIgnoreRightClickInWindowlessMode = 1 << 15
+ };
+
+ class PluginQuirkSet {
+ public:
+ PluginQuirkSet() : m_quirks(0) { }
+ void add(PluginQuirk quirk) { m_quirks |= quirk; }
+ bool contains(PluginQuirk quirk) const { return m_quirks & quirk; }
+ private:
+ unsigned m_quirks;
+ };
+
+} // namespace WebCore
+
+#endif // PluginQuirkSet_h
diff --git a/Source/WebCore/plugins/PluginStrategy.h b/Source/WebCore/plugins/PluginStrategy.h
new file mode 100644
index 0000000..9d8a7b5
--- /dev/null
+++ b/Source/WebCore/plugins/PluginStrategy.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginStrategy_h
+#define PluginStrategy_h
+
+#if USE(PLATFORM_STRATEGIES)
+
+#include "PluginData.h"
+
+namespace WebCore {
+
+class Page;
+
+class PluginStrategy {
+public:
+ virtual void refreshPlugins() = 0;
+ virtual void getPluginInfo(const Page*, Vector<PluginInfo>&) = 0;
+
+protected:
+ virtual ~PluginStrategy() { }
+};
+
+} // namespace WebCore
+
+#endif // USE(PLATFORM_STRATEGIES)
+
+#endif // PluginStrategy_h
diff --git a/Source/WebCore/plugins/PluginStream.cpp b/Source/WebCore/plugins/PluginStream.cpp
new file mode 100644
index 0000000..f9021a8
--- /dev/null
+++ b/Source/WebCore/plugins/PluginStream.cpp
@@ -0,0 +1,508 @@
+/*
+ * 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 "PluginStream.h"
+
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "PluginDebug.h"
+#include "ResourceLoadScheduler.h"
+#include "SharedBuffer.h"
+#include "SubresourceLoader.h"
+#include <StringExtras.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+
+// We use -2 here because some plugins like to return -1 to indicate error
+// and this way we won't clash with them.
+static const int WebReasonNone = -2;
+
+using std::max;
+using std::min;
+
+namespace WebCore {
+
+typedef HashMap<NPStream*, NPP> StreamMap;
+static StreamMap& streams()
+{
+ static StreamMap staticStreams;
+ return staticStreams;
+}
+
+PluginStream::PluginStream(PluginStreamClient* client, Frame* frame, const ResourceRequest& resourceRequest, bool sendNotification, void* notifyData, const NPPluginFuncs* pluginFuncs, NPP instance, const PluginQuirkSet& quirks)
+ : m_resourceRequest(resourceRequest)
+ , m_client(client)
+ , m_frame(frame)
+ , m_notifyData(notifyData)
+ , m_sendNotification(sendNotification)
+ , m_streamState(StreamBeforeStarted)
+ , m_loadManually(false)
+ , m_delayDeliveryTimer(this, &PluginStream::delayDeliveryTimerFired)
+ , m_deliveryData(0)
+ , m_tempFileHandle(invalidPlatformFileHandle)
+ , m_pluginFuncs(pluginFuncs)
+ , m_instance(instance)
+ , m_quirks(quirks)
+{
+ ASSERT(m_instance);
+
+ m_stream.url = 0;
+ m_stream.ndata = 0;
+ m_stream.pdata = 0;
+ m_stream.end = 0;
+ m_stream.notifyData = 0;
+ m_stream.lastmodified = 0;
+
+ streams().add(&m_stream, m_instance);
+}
+
+PluginStream::~PluginStream()
+{
+ ASSERT(m_streamState != StreamStarted);
+ ASSERT(!m_loader);
+
+ fastFree((char*)m_stream.url);
+
+ streams().remove(&m_stream);
+}
+
+void PluginStream::start()
+{
+ ASSERT(!m_loadManually);
+ m_loader = resourceLoadScheduler()->schedulePluginStreamLoad(m_frame, this, m_resourceRequest);
+}
+
+void PluginStream::stop()
+{
+ m_streamState = StreamStopped;
+
+ if (m_loadManually) {
+ ASSERT(!m_loader);
+
+ DocumentLoader* documentLoader = m_frame->loader()->activeDocumentLoader();
+ ASSERT(documentLoader);
+
+ if (documentLoader->isLoadingMainResource())
+ documentLoader->cancelMainResourceLoad(m_frame->loader()->cancelledError(m_resourceRequest));
+
+ return;
+ }
+
+ if (m_loader) {
+ m_loader->cancel();
+ m_loader = 0;
+ }
+
+ m_client = 0;
+}
+
+void PluginStream::startStream()
+{
+ ASSERT(m_streamState == StreamBeforeStarted);
+
+ const KURL& responseURL = m_resourceResponse.url();
+
+ // Some plugins (Flash) expect that javascript URLs are passed back decoded as this is the
+ // format used when requesting the URL.
+ if (protocolIsJavaScript(responseURL))
+ m_stream.url = fastStrDup(decodeURLEscapeSequences(responseURL.string()).utf8().data());
+ else
+ m_stream.url = fastStrDup(responseURL.string().utf8().data());
+
+ CString mimeTypeStr = m_resourceResponse.mimeType().utf8();
+
+ long long expectedContentLength = m_resourceResponse.expectedContentLength();
+
+ if (m_resourceResponse.isHTTP()) {
+ Vector<UChar> stringBuilder;
+ String separator(": ");
+
+ String statusLine = makeString("HTTP ", String::number(m_resourceResponse.httpStatusCode()), " OK\n");
+ stringBuilder.append(statusLine.characters(), statusLine.length());
+
+ HTTPHeaderMap::const_iterator end = m_resourceResponse.httpHeaderFields().end();
+ for (HTTPHeaderMap::const_iterator it = m_resourceResponse.httpHeaderFields().begin(); it != end; ++it) {
+ stringBuilder.append(it->first.characters(), it->first.length());
+ stringBuilder.append(separator.characters(), separator.length());
+ stringBuilder.append(it->second.characters(), it->second.length());
+ stringBuilder.append('\n');
+ }
+
+ m_headers = String::adopt(stringBuilder).utf8();
+
+ // If the content is encoded (most likely compressed), then don't send its length to the plugin,
+ // which is only interested in the decoded length, not yet known at the moment.
+ // <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic.
+ String contentEncoding = m_resourceResponse.httpHeaderField("Content-Encoding");
+ if (!contentEncoding.isNull() && contentEncoding != "identity")
+ expectedContentLength = -1;
+ }
+
+ m_stream.headers = m_headers.data();
+ m_stream.pdata = 0;
+ m_stream.ndata = this;
+ m_stream.end = max(expectedContentLength, 0LL);
+ m_stream.lastmodified = m_resourceResponse.lastModifiedDate();
+ m_stream.notifyData = m_notifyData;
+
+ m_transferMode = NP_NORMAL;
+ m_offset = 0;
+ m_reason = WebReasonNone;
+
+ // Protect the stream if destroystream is called from within the newstream handler
+ RefPtr<PluginStream> protect(this);
+
+ // calling into a plug-in could result in re-entrance if the plug-in yields
+ // control to the system (rdar://5744899). prevent this by deferring further
+ // loading while calling into the plug-in.
+ if (m_loader)
+ m_loader->setDefersLoading(true);
+ NPError npErr = m_pluginFuncs->newstream(m_instance, (NPMIMEType)mimeTypeStr.data(), &m_stream, false, &m_transferMode);
+ if (m_loader)
+ m_loader->setDefersLoading(false);
+
+ // If the stream was destroyed in the call to newstream we return
+ if (m_reason != WebReasonNone)
+ return;
+
+ if (npErr != NPERR_NO_ERROR) {
+ cancelAndDestroyStream(npErr);
+ return;
+ }
+
+ m_streamState = StreamStarted;
+
+ if (m_transferMode == NP_NORMAL)
+ return;
+
+ m_path = openTemporaryFile("WKP", m_tempFileHandle);
+
+ // Something went wrong, cancel loading the stream
+ if (!isHandleValid(m_tempFileHandle))
+ cancelAndDestroyStream(NPRES_NETWORK_ERR);
+}
+
+NPP PluginStream::ownerForStream(NPStream* stream)
+{
+ return streams().get(stream);
+}
+
+void PluginStream::cancelAndDestroyStream(NPReason reason)
+{
+ RefPtr<PluginStream> protect(this);
+
+ destroyStream(reason);
+ stop();
+}
+
+void PluginStream::destroyStream(NPReason reason)
+{
+ m_reason = reason;
+ if (m_reason != NPRES_DONE) {
+ // Stop any pending data from being streamed
+ if (m_deliveryData)
+ m_deliveryData->resize(0);
+ } else if (m_deliveryData && m_deliveryData->size() > 0) {
+ // There is more data to be streamed, don't destroy the stream now.
+ return;
+ }
+ destroyStream();
+}
+
+void PluginStream::destroyStream()
+{
+ if (m_streamState == StreamStopped)
+ return;
+
+ ASSERT(m_reason != WebReasonNone);
+ ASSERT(!m_deliveryData || m_deliveryData->size() == 0);
+
+ closeFile(m_tempFileHandle);
+
+ bool newStreamCalled = m_stream.ndata;
+
+ // Protect from destruction if:
+ // NPN_DestroyStream is called from NPP_NewStream or
+ // PluginStreamClient::streamDidFinishLoading() removes the last reference
+ RefPtr<PluginStream> protect(this);
+
+ if (newStreamCalled) {
+ if (m_reason == NPRES_DONE && (m_transferMode == NP_ASFILE || m_transferMode == NP_ASFILEONLY)) {
+ ASSERT(!m_path.isNull());
+
+ if (m_loader)
+ m_loader->setDefersLoading(true);
+ m_pluginFuncs->asfile(m_instance, &m_stream, m_path.data());
+ if (m_loader)
+ m_loader->setDefersLoading(false);
+ }
+
+ if (m_streamState != StreamBeforeStarted) {
+ if (m_loader)
+ m_loader->setDefersLoading(true);
+
+ NPError npErr = m_pluginFuncs->destroystream(m_instance, &m_stream, m_reason);
+
+ if (m_loader)
+ m_loader->setDefersLoading(false);
+
+ LOG_NPERROR(npErr);
+ }
+
+ m_stream.ndata = 0;
+ }
+
+ if (m_sendNotification) {
+ // Flash 9 can dereference null if we call NPP_URLNotify without first calling NPP_NewStream
+ // for requests made with NPN_PostURLNotify; see <rdar://5588807>
+ if (m_loader)
+ m_loader->setDefersLoading(true);
+ if (!newStreamCalled && m_quirks.contains(PluginQuirkFlashURLNotifyBug) &&
+ equalIgnoringCase(m_resourceRequest.httpMethod(), "POST")) {
+ m_transferMode = NP_NORMAL;
+ m_stream.url = "";
+ m_stream.notifyData = m_notifyData;
+
+ static char emptyMimeType[] = "";
+ m_pluginFuncs->newstream(m_instance, emptyMimeType, &m_stream, false, &m_transferMode);
+ m_pluginFuncs->destroystream(m_instance, &m_stream, m_reason);
+
+ // in successful requests, the URL is dynamically allocated and freed in our
+ // destructor, so reset it to 0
+ m_stream.url = 0;
+ }
+ m_pluginFuncs->urlnotify(m_instance, m_resourceRequest.url().string().utf8().data(), m_reason, m_notifyData);
+ if (m_loader)
+ m_loader->setDefersLoading(false);
+ }
+
+ m_streamState = StreamStopped;
+
+ if (!m_loadManually && m_client)
+ m_client->streamDidFinishLoading(this);
+
+ if (!m_path.isNull()) {
+ String tempFilePath = String::fromUTF8(m_path.data());
+ deleteFile(tempFilePath);
+ }
+}
+
+void PluginStream::delayDeliveryTimerFired(Timer<PluginStream>* timer)
+{
+ ASSERT(timer == &m_delayDeliveryTimer);
+
+ deliverData();
+}
+
+void PluginStream::deliverData()
+{
+ ASSERT(m_deliveryData);
+
+ if (m_streamState == StreamStopped)
+ // FIXME: We should cancel our job in the SubresourceLoader on error so we don't reach this case
+ return;
+
+ ASSERT(m_streamState != StreamBeforeStarted);
+
+ if (!m_stream.ndata || m_deliveryData->size() == 0)
+ return;
+
+ int32_t totalBytes = m_deliveryData->size();
+ int32_t totalBytesDelivered = 0;
+
+ if (m_loader)
+ m_loader->setDefersLoading(true);
+ while (totalBytesDelivered < totalBytes) {
+ int32_t deliveryBytes = m_pluginFuncs->writeready(m_instance, &m_stream);
+
+ if (deliveryBytes <= 0) {
+#if PLATFORM(ANDROID)
+// TODO: This needs to be upstreamed.
+ if (m_loader)
+ m_loader->pauseLoad(true);
+
+ // ask the plugin for a delay value.
+ int delay = deliveryDelay();
+ m_delayDeliveryTimer.startOneShot(delay * 0.001);
+#else
+ m_delayDeliveryTimer.startOneShot(0);
+#endif
+ break;
+ } else {
+ deliveryBytes = min(deliveryBytes, totalBytes - totalBytesDelivered);
+ int32_t dataLength = deliveryBytes;
+ char* data = m_deliveryData->data() + totalBytesDelivered;
+
+ // Write the data
+ deliveryBytes = m_pluginFuncs->write(m_instance, &m_stream, m_offset, dataLength, (void*)data);
+ if (deliveryBytes < 0) {
+ LOG_PLUGIN_NET_ERROR();
+ if (m_loader)
+ m_loader->setDefersLoading(false);
+ cancelAndDestroyStream(NPRES_NETWORK_ERR);
+ return;
+ }
+ deliveryBytes = min(deliveryBytes, dataLength);
+ m_offset += deliveryBytes;
+ totalBytesDelivered += deliveryBytes;
+ }
+ }
+ if (m_loader)
+ m_loader->setDefersLoading(false);
+
+ if (totalBytesDelivered > 0) {
+ if (totalBytesDelivered < totalBytes) {
+ int remainingBytes = totalBytes - totalBytesDelivered;
+ memmove(m_deliveryData->data(), m_deliveryData->data() + totalBytesDelivered, remainingBytes);
+ m_deliveryData->resize(remainingBytes);
+ } else {
+#if PLATFORM(ANDROID)
+//TODO: This needs to be upstreamed to WebKit.
+ if (m_loader)
+ m_loader->pauseLoad(false);
+#endif
+ m_deliveryData->resize(0);
+ if (m_reason != WebReasonNone)
+ destroyStream();
+ }
+ }
+}
+
+void PluginStream::sendJavaScriptStream(const KURL& requestURL, const CString& resultString)
+{
+ didReceiveResponse(0, ResourceResponse(requestURL, "text/plain", resultString.length(), "", ""));
+
+ if (m_streamState == StreamStopped)
+ return;
+
+ if (!resultString.isNull()) {
+ didReceiveData(0, resultString.data(), resultString.length());
+ if (m_streamState == StreamStopped)
+ return;
+ }
+
+ m_loader = 0;
+
+ destroyStream(resultString.isNull() ? NPRES_NETWORK_ERR : NPRES_DONE);
+}
+
+void PluginStream::didReceiveResponse(NetscapePlugInStreamLoader* loader, const ResourceResponse& response)
+{
+ ASSERT(loader == m_loader);
+ ASSERT(m_streamState == StreamBeforeStarted);
+
+ m_resourceResponse = response;
+
+ startStream();
+}
+
+void PluginStream::didReceiveData(NetscapePlugInStreamLoader* loader, const char* data, int length)
+{
+ ASSERT(loader == m_loader);
+ ASSERT(m_streamState == StreamStarted);
+
+ // If the plug-in cancels the stream in deliverData it could be deleted,
+ // so protect it here.
+ RefPtr<PluginStream> protect(this);
+
+ if (m_transferMode != NP_ASFILEONLY) {
+ if (!m_deliveryData)
+ m_deliveryData.set(new Vector<char>);
+
+ int oldSize = m_deliveryData->size();
+ m_deliveryData->resize(oldSize + length);
+ memcpy(m_deliveryData->data() + oldSize, data, length);
+
+#if PLATFORM(ANDROID)
+//TODO: This needs to be upstreamed to WebKit.
+ if (!m_delayDeliveryTimer.isActive())
+#endif
+ deliverData();
+ }
+
+ if (m_streamState != StreamStopped && isHandleValid(m_tempFileHandle)) {
+ int bytesWritten = writeToFile(m_tempFileHandle, data, length);
+ if (bytesWritten != length)
+ cancelAndDestroyStream(NPRES_NETWORK_ERR);
+ }
+}
+
+void PluginStream::didFail(NetscapePlugInStreamLoader* loader, const ResourceError&)
+{
+ ASSERT(loader == m_loader);
+
+ LOG_PLUGIN_NET_ERROR();
+
+ // destroyStream can result in our being deleted
+ RefPtr<PluginStream> protect(this);
+
+ destroyStream(NPRES_NETWORK_ERR);
+
+ m_loader = 0;
+}
+
+void PluginStream::didFinishLoading(NetscapePlugInStreamLoader* loader)
+{
+ ASSERT(loader == m_loader);
+ ASSERT(m_streamState == StreamStarted);
+
+ // destroyStream can result in our being deleted
+ RefPtr<PluginStream> protect(this);
+
+ destroyStream(NPRES_DONE);
+
+ m_loader = 0;
+}
+
+bool PluginStream::wantsAllStreams() const
+{
+ if (!m_pluginFuncs->getvalue)
+ return false;
+
+ void* result = 0;
+ if (m_pluginFuncs->getvalue(m_instance, NPPVpluginWantsAllNetworkStreams, &result) != NPERR_NO_ERROR)
+ return false;
+
+ return result != 0;
+}
+
+#if PLATFORM(ANDROID)
+int PluginStream::deliveryDelay() const
+{
+ if (!m_pluginFuncs->getvalue)
+ return 0;
+
+ int delay = 0;
+ if (m_pluginFuncs->getvalue(m_instance, NPPDataDeliveryDelayMs, &delay) != NPERR_NO_ERROR)
+ return 0;
+
+ return delay;
+}
+#endif
+
+}
diff --git a/Source/WebCore/plugins/PluginStream.h b/Source/WebCore/plugins/PluginStream.h
new file mode 100644
index 0000000..ae69539
--- /dev/null
+++ b/Source/WebCore/plugins/PluginStream.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#ifndef PluginStream_h
+#define PluginStream_h
+
+#include "FileSystem.h"
+#include "KURL.h"
+#include "NetscapePlugInStreamLoader.h"
+#include "PlatformString.h"
+#include "PluginQuirkSet.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include "Timer.h"
+#include "npruntime_internal.h"
+#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+ class Frame;
+ class PluginStream;
+
+ enum PluginStreamState { StreamBeforeStarted, StreamStarted, StreamStopped };
+
+ class PluginStreamClient {
+ public:
+ virtual ~PluginStreamClient() {}
+ virtual void streamDidFinishLoading(PluginStream*) {}
+ };
+
+ class PluginStream : public RefCounted<PluginStream>, private NetscapePlugInStreamLoaderClient {
+ public:
+ static PassRefPtr<PluginStream> create(PluginStreamClient* client, Frame* frame, const ResourceRequest& request, bool sendNotification, void* notifyData, const NPPluginFuncs* functions, NPP instance, const PluginQuirkSet& quirks)
+ {
+ return adoptRef(new PluginStream(client, frame, request, sendNotification, notifyData, functions, instance, quirks));
+ }
+ virtual ~PluginStream();
+
+ void start();
+ void stop();
+
+ void startStream();
+
+ void setLoadManually(bool loadManually) { m_loadManually = loadManually; }
+
+ void sendJavaScriptStream(const KURL& requestURL, const WTF::CString& resultString);
+ void cancelAndDestroyStream(NPReason);
+
+ static NPP ownerForStream(NPStream*);
+
+ // NetscapePlugInStreamLoaderClient
+ virtual void didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse&);
+ virtual void didReceiveData(NetscapePlugInStreamLoader*, const char*, int);
+ virtual void didFail(NetscapePlugInStreamLoader*, const ResourceError&);
+ virtual void didFinishLoading(NetscapePlugInStreamLoader*);
+ virtual bool wantsAllStreams() const;
+
+ private:
+ PluginStream(PluginStreamClient*, Frame*, const ResourceRequest&, bool sendNotification, void* notifyData, const NPPluginFuncs*, NPP instance, const PluginQuirkSet&);
+
+ void deliverData();
+ void destroyStream(NPReason);
+ void destroyStream();
+#if PLATFORM(ANDROID)
+ int deliveryDelay() const;
+#endif
+ ResourceRequest m_resourceRequest;
+ ResourceResponse m_resourceResponse;
+
+ PluginStreamClient* m_client;
+ Frame* m_frame;
+ RefPtr<NetscapePlugInStreamLoader> m_loader;
+ void* m_notifyData;
+ bool m_sendNotification;
+ PluginStreamState m_streamState;
+ bool m_loadManually;
+
+ Timer<PluginStream> m_delayDeliveryTimer;
+ void delayDeliveryTimerFired(Timer<PluginStream>*);
+
+ OwnPtr< Vector<char> > m_deliveryData;
+
+ PlatformFileHandle m_tempFileHandle;
+
+ const NPPluginFuncs* m_pluginFuncs;
+ NPP m_instance;
+ uint16_t m_transferMode;
+ int32_t m_offset;
+ WTF::CString m_headers;
+ WTF::CString m_path;
+ NPReason m_reason;
+ NPStream m_stream;
+ PluginQuirkSet m_quirks;
+ };
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/plugins/PluginView.cpp b/Source/WebCore/plugins/PluginView.cpp
new file mode 100644
index 0000000..f06daf4
--- /dev/null
+++ b/Source/WebCore/plugins/PluginView.cpp
@@ -0,0 +1,1620 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2010 Girish Ramakrishnan <girish@forwardbias.in>
+ *
+ * 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"
+
+#if USE(JSC)
+#include "Bridge.h"
+#endif
+#include "Chrome.h"
+#include "CookieJar.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
+#include "Image.h"
+#include "KeyboardEvent.h"
+#include "MIMETypeRegistry.h"
+#include "MouseEvent.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PluginDatabase.h"
+#include "PluginDebug.h"
+#include "PluginMainThreadScheduler.h"
+#include "PluginPackage.h"
+#include "ProxyServer.h"
+#include "RenderBox.h"
+#include "RenderObject.h"
+#include "ScriptController.h"
+#include "ScriptValue.h"
+#include "SecurityOrigin.h"
+#include "Settings.h"
+#include "npruntime_impl.h"
+#include <wtf/ASCIICType.h>
+
+#if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
+#include "PluginMessageThrottlerWin.h"
+#endif
+
+#if defined(ANDROID_PLUGINS)
+#include "TouchEvent.h"
+#endif
+
+#if USE(JSC)
+#include "JSDOMBinding.h"
+#include "JSDOMWindow.h"
+#include "c_instance.h"
+#include "runtime_root.h"
+#include <runtime/JSLock.h>
+#include <runtime/JSValue.h>
+
+using JSC::ExecState;
+using JSC::JSLock;
+using JSC::JSObject;
+using JSC::JSValue;
+using JSC::UString;
+#endif
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+
+using std::min;
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static int s_callingPlugin;
+
+typedef HashMap<NPP, PluginView*> InstanceMap;
+
+static InstanceMap& instanceMap()
+{
+ static InstanceMap& map = *new InstanceMap;
+ return map;
+}
+
+static String scriptStringIfJavaScriptURL(const KURL& url)
+{
+ if (!protocolIsJavaScript(url))
+ return String();
+
+ // This returns an unescaped string
+ return decodeURLEscapeSequences(url.string().substring(11));
+}
+
+PluginView* PluginView::s_currentPluginView = 0;
+
+void PluginView::popPopupsStateTimerFired(Timer<PluginView>*)
+{
+ popPopupsEnabledState();
+}
+
+IntRect PluginView::windowClipRect() const
+{
+ // Start by clipping to our bounds.
+ IntRect clipRect(m_windowRect);
+
+ // Take our element and get the clip rect from the enclosing layer and frame view.
+ RenderLayer* layer = m_element->renderer()->enclosingLayer();
+ FrameView* parentView = m_element->document()->view();
+ clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
+
+ return clipRect;
+}
+
+void PluginView::setFrameRect(const IntRect& rect)
+{
+ if (m_element->document()->printing())
+ return;
+
+ if (rect != frameRect())
+ Widget::setFrameRect(rect);
+
+ updatePluginWidget();
+
+#if OS(WINDOWS) || OS(SYMBIAN)
+ // On Windows and Symbian, always call plugin to change geometry.
+ setNPWindowRect(rect);
+#elif defined(XP_UNIX)
+ // On Unix, multiple calls to setNPWindow() in windowed mode causes Flash to crash
+ if (m_mode == NP_FULL || !m_isWindowed)
+ setNPWindowRect(rect);
+#endif
+}
+
+void PluginView::frameRectsChanged()
+{
+ updatePluginWidget();
+}
+
+void PluginView::handleEvent(Event* event)
+{
+ if (!m_plugin || m_isWindowed)
+ return;
+
+ // Protect the plug-in from deletion while dispatching the event.
+ RefPtr<PluginView> protect(this);
+
+ if (event->isMouseEvent())
+ handleMouseEvent(static_cast<MouseEvent*>(event));
+ else if (event->isKeyboardEvent())
+ handleKeyboardEvent(static_cast<KeyboardEvent*>(event));
+#if defined(ANDROID_PLUGINS)
+#if ENABLE(TOUCH_EVENTS)
+ else if (event->isTouchEvent())
+ handleTouchEvent(static_cast<TouchEvent*>(event));
+#endif
+ else if (event->type() == eventNames().DOMFocusOutEvent)
+ handleFocusEvent(false);
+ else if (event->type() == eventNames().DOMFocusInEvent)
+ handleFocusEvent(true);
+#endif
+#if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
+ else if (event->type() == eventNames().focusoutEvent)
+ handleFocusOutEvent();
+ else if (event->type() == eventNames().focusinEvent)
+ handleFocusInEvent();
+#endif
+}
+
+void PluginView::init()
+{
+ if (m_haveInitialized)
+ return;
+
+ m_haveInitialized = true;
+
+ if (!m_plugin) {
+ ASSERT(m_status == PluginStatusCanNotFindPlugin);
+ return;
+ }
+
+ LOG(Plugins, "PluginView::init(): Initializing plug-in '%s'", m_plugin->name().utf8().data());
+
+ if (!m_plugin->load()) {
+ m_plugin = 0;
+ m_status = PluginStatusCanNotLoadPlugin;
+ return;
+ }
+
+ if (!startOrAddToUnstartedList()) {
+ m_status = PluginStatusCanNotLoadPlugin;
+ return;
+ }
+
+ m_status = PluginStatusLoadedSuccessfully;
+}
+
+bool PluginView::startOrAddToUnstartedList()
+{
+ if (!m_parentFrame->page())
+ return false;
+
+ // We only delay starting the plug-in if we're going to kick off the load
+ // ourselves. Otherwise, the loader will try to deliver data before we've
+ // started the plug-in.
+ if (!m_loadManually && !m_parentFrame->page()->canStartMedia()) {
+ m_parentFrame->document()->addMediaCanStartListener(this);
+ m_isWaitingToStart = true;
+ return true;
+ }
+
+ return start();
+}
+
+bool PluginView::start()
+{
+ if (m_isStarted)
+ return false;
+
+ m_isWaitingToStart = false;
+
+ PluginMainThreadScheduler::scheduler().registerPlugin(m_instance);
+
+ ASSERT(m_plugin);
+ ASSERT(m_plugin->pluginFuncs()->newp);
+
+ NPError npErr;
+ {
+ PluginView::setCurrentPluginView(this);
+#if USE(JSC)
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+#endif
+ setCallingPlugin(true);
+ npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.utf8().data(), m_instance, m_mode, m_paramCount, m_paramNames, m_paramValues, NULL);
+ setCallingPlugin(false);
+ LOG_NPERROR(npErr);
+ PluginView::setCurrentPluginView(0);
+ }
+
+ if (npErr != NPERR_NO_ERROR) {
+ m_status = PluginStatusCanNotLoadPlugin;
+ PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
+ return false;
+ }
+
+ m_isStarted = true;
+
+ if (!m_url.isEmpty() && !m_loadManually) {
+ FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin());
+ frameLoadRequest.resourceRequest().setHTTPMethod("GET");
+ frameLoadRequest.resourceRequest().setURL(m_url);
+#ifdef ANDROID_PLUGINS
+ if (!SecurityOrigin::shouldHideReferrer(
+ m_url, m_parentFrame->loader()->outgoingReferrer()))
+ frameLoadRequest.resourceRequest().setHTTPReferrer(
+ m_parentFrame->loader()->outgoingReferrer());
+#endif
+ load(frameLoadRequest, false, 0);
+ }
+
+ m_status = PluginStatusLoadedSuccessfully;
+
+ if (!platformStart())
+ m_status = PluginStatusCanNotLoadPlugin;
+
+ if (m_status != PluginStatusLoadedSuccessfully)
+ return false;
+
+ if (parentFrame()->page())
+ parentFrame()->page()->didStartPlugin(this);
+
+ return true;
+}
+
+void PluginView::mediaCanStart()
+{
+ ASSERT(!m_isStarted);
+ if (!start())
+ parentFrame()->loader()->client()->dispatchDidFailToStartPlugin(this);
+}
+
+PluginView::~PluginView()
+{
+ LOG(Plugins, "PluginView::~PluginView()");
+
+ ASSERT(!m_lifeSupportTimer.isActive());
+
+ // If we failed to find the plug-in, we'll return early in our constructor, and
+ // m_instance will be 0.
+ if (m_instance)
+ instanceMap().remove(m_instance);
+
+ if (m_isWaitingToStart)
+ m_parentFrame->document()->removeMediaCanStartListener(this);
+
+ stop();
+
+ deleteAllValues(m_requests);
+
+ freeStringArray(m_paramNames, m_paramCount);
+ freeStringArray(m_paramValues, m_paramCount);
+
+ platformDestroy();
+
+ m_parentFrame->script()->cleanupScriptObjectsForPlugin(this);
+
+#if PLATFORM(ANDROID)
+ // Since we have no legacy plugins to check, we ignore the quirks check.
+ if (m_plugin)
+#else
+ if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin)))
+#endif
+ m_plugin->unload();
+}
+
+void PluginView::stop()
+{
+ if (!m_isStarted)
+ return;
+
+ if (parentFrame()->page())
+ parentFrame()->page()->didStopPlugin(this);
+
+ LOG(Plugins, "PluginView::stop(): Stopping plug-in '%s'", m_plugin->name().utf8().data());
+
+ 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;
+
+#if USE(JSC)
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+#endif
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+#ifdef XP_WIN
+ // Unsubclass the window
+ if (m_isWindowed) {
+#if OS(WINCE)
+ WNDPROC currentWndProc = (WNDPROC)GetWindowLong(platformPluginWidget(), GWL_WNDPROC);
+
+ if (currentWndProc == PluginViewWndProc)
+ SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)m_pluginWndProc);
+#else
+ WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
+
+ if (currentWndProc == PluginViewWndProc)
+ SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)m_pluginWndProc);
+#endif
+ }
+#endif // XP_WIN
+#endif // ENABLE(NETSCAPE_PLUGIN_API)
+
+#if !defined(XP_MACOSX)
+ // Clear the window
+ m_npWindow.window = 0;
+
+ if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) {
+ PluginView::setCurrentPluginView(this);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ }
+
+#ifdef XP_UNIX
+ if (m_isWindowed && m_npWindow.ws_info)
+ delete (NPSetWindowCallbackStruct *)m_npWindow.ws_info;
+ m_npWindow.ws_info = 0;
+#endif
+
+#endif // !defined(XP_MACOSX)
+
+ PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
+
+ NPSavedData* savedData = 0;
+ PluginView::setCurrentPluginView(this);
+ setCallingPlugin(true);
+ NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
+ setCallingPlugin(false);
+ LOG_NPERROR(npErr);
+ PluginView::setCurrentPluginView(0);
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ if (savedData) {
+ // TODO: Actually save this data instead of just discarding it
+ if (savedData->buf)
+ NPN_MemFree(savedData->buf);
+ NPN_MemFree(savedData);
+ }
+#endif
+
+ m_instance->pdata = 0;
+}
+
+void PluginView::setCurrentPluginView(PluginView* pluginView)
+{
+ s_currentPluginView = pluginView;
+}
+
+PluginView* PluginView::currentPluginView()
+{
+ return s_currentPluginView;
+}
+
+static char* createUTF8String(const String& str)
+{
+ CString cstr = str.utf8();
+ char* result = reinterpret_cast<char*>(fastMalloc(cstr.length() + 1));
+
+ strncpy(result, cstr.data(), cstr.length() + 1);
+
+ return result;
+}
+
+void PluginView::performRequest(PluginRequest* request)
+{
+ if (!m_isStarted)
+ return;
+
+ // don't let a plugin start any loads if it is no longer part of a document that is being
+ // displayed unless the loads are in the same frame as the plugin.
+ const String& targetFrameName = request->frameLoadRequest().frameName();
+ if (m_parentFrame->loader()->documentLoader() != m_parentFrame->loader()->activeDocumentLoader() &&
+ (targetFrameName.isNull() || m_parentFrame->tree()->find(targetFrameName) != m_parentFrame))
+ return;
+
+ KURL requestURL = request->frameLoadRequest().resourceRequest().url();
+ String jsString = scriptStringIfJavaScriptURL(requestURL);
+
+ if (jsString.isNull()) {
+ // if this is not a targeted request, create a stream for it. otherwise,
+ // just pass it off to the loader
+ if (targetFrameName.isEmpty()) {
+ RefPtr<PluginStream> stream = PluginStream::create(this, m_parentFrame.get(), request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
+ m_streams.add(stream);
+ stream->start();
+ } else {
+ // If the target frame is our frame, we could destroy the
+ // PluginView, so we protect it. <rdar://problem/6991251>
+ RefPtr<PluginView> protect(this);
+
+ m_parentFrame->loader()->load(request->frameLoadRequest().resourceRequest(), targetFrameName, false);
+
+ // FIXME: <rdar://problem/4807469> This should be sent when the document has finished loading
+ if (request->sendNotification()) {
+ PluginView::setCurrentPluginView(this);
+#if USE(JSC)
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+#endif
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->urlnotify(m_instance, requestURL.string().utf8().data(), NPRES_DONE, request->notifyData());
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ }
+ }
+ return;
+ }
+
+ // Targeted JavaScript requests are only allowed on the frame that contains the JavaScript plugin
+ // and this has been made sure in ::load.
+ ASSERT(targetFrameName.isEmpty() || m_parentFrame->tree()->find(targetFrameName) == m_parentFrame);
+
+ // Executing a script can cause the plugin view to be destroyed, so we keep a reference to the parent frame.
+ RefPtr<Frame> parentFrame = m_parentFrame;
+ ScriptValue result = m_parentFrame->script()->executeScript(jsString, request->shouldAllowPopups());
+
+ if (targetFrameName.isNull()) {
+ String resultString;
+
+#if USE(JSC)
+ ScriptState* scriptState = parentFrame->script()->globalObject(pluginWorld())->globalExec();
+#elif USE(V8)
+ ScriptState* scriptState = 0; // Not used with V8
+#endif
+ CString cstr;
+ if (result.getString(scriptState, resultString))
+ cstr = resultString.utf8();
+
+ RefPtr<PluginStream> stream = PluginStream::create(this, m_parentFrame.get(), request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
+ m_streams.add(stream);
+ stream->sendJavaScriptStream(requestURL, cstr);
+ }
+}
+
+void PluginView::requestTimerFired(Timer<PluginView>* timer)
+{
+ ASSERT(timer == &m_requestTimer);
+ ASSERT(m_requests.size() > 0);
+ ASSERT(!m_isJavaScriptPaused);
+
+ PluginRequest* request = m_requests[0];
+ m_requests.remove(0);
+
+ // Schedule a new request before calling performRequest since the call to
+ // performRequest can cause the plugin view to be deleted.
+ if (m_requests.size() > 0)
+ m_requestTimer.startOneShot(0);
+
+ performRequest(request);
+ delete request;
+}
+
+void PluginView::scheduleRequest(PluginRequest* request)
+{
+ m_requests.append(request);
+
+ if (!m_isJavaScriptPaused)
+ m_requestTimer.startOneShot(0);
+}
+
+NPError PluginView::load(const FrameLoadRequest& frameLoadRequest, bool sendNotification, void* notifyData)
+{
+ ASSERT(frameLoadRequest.resourceRequest().httpMethod() == "GET" || frameLoadRequest.resourceRequest().httpMethod() == "POST");
+
+ KURL url = frameLoadRequest.resourceRequest().url();
+
+ if (url.isEmpty())
+ return NPERR_INVALID_URL;
+
+ // Don't allow requests to be made when the document loader is stopping all loaders.
+ DocumentLoader* loader = m_parentFrame->loader()->documentLoader();
+ if (!loader || loader->isStopping())
+ return NPERR_GENERIC_ERROR;
+
+ const String& targetFrameName = frameLoadRequest.frameName();
+ String jsString = scriptStringIfJavaScriptURL(url);
+
+ if (!jsString.isNull()) {
+ // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
+ if (!m_parentFrame->script()->canExecuteScripts(NotAboutToExecuteScript))
+ return NPERR_GENERIC_ERROR;
+
+ // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
+ if (!targetFrameName.isNull() && m_parentFrame->tree()->find(targetFrameName) != m_parentFrame)
+ return NPERR_INVALID_PARAM;
+ } else if (!m_parentFrame->document()->securityOrigin()->canDisplay(url))
+ return NPERR_GENERIC_ERROR;
+
+ PluginRequest* request = new PluginRequest(frameLoadRequest, sendNotification, notifyData, arePopupsAllowed());
+ scheduleRequest(request);
+
+ return NPERR_NO_ERROR;
+}
+
+static KURL makeURL(const KURL& baseURL, const char* relativeURLString)
+{
+ String urlString = relativeURLString;
+
+ // Strip return characters.
+ urlString.replace('\n', "");
+ urlString.replace('\r', "");
+
+ return KURL(baseURL, urlString);
+}
+
+NPError PluginView::getURLNotify(const char* url, const char* target, void* notifyData)
+{
+ FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin());
+
+ frameLoadRequest.setFrameName(target);
+ frameLoadRequest.resourceRequest().setHTTPMethod("GET");
+ frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url));
+#ifdef ANDROID_PLUGINS
+ if (!SecurityOrigin::shouldHideReferrer(
+ frameLoadRequest.resourceRequest().url(), m_url))
+ frameLoadRequest.resourceRequest().setHTTPReferrer(m_url);
+#endif
+
+ return load(frameLoadRequest, true, notifyData);
+}
+
+NPError PluginView::getURL(const char* url, const char* target)
+{
+ FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin());
+
+ frameLoadRequest.setFrameName(target);
+ frameLoadRequest.resourceRequest().setHTTPMethod("GET");
+ frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url));
+#ifdef ANDROID_PLUGINS
+ if (!SecurityOrigin::shouldHideReferrer(
+ frameLoadRequest.resourceRequest().url(), m_url))
+ frameLoadRequest.resourceRequest().setHTTPReferrer(m_url);
+#endif
+
+ return load(frameLoadRequest, false, 0);
+}
+
+NPError PluginView::postURLNotify(const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData)
+{
+ return handlePost(url, target, len, buf, file, notifyData, true, true);
+}
+
+NPError PluginView::postURL(const char* url, const char* target, uint32_t len, const char* buf, NPBool file)
+{
+ // As documented, only allow headers to be specified via NPP_PostURL when using a file.
+ return handlePost(url, target, len, buf, file, 0, false, file);
+}
+
+NPError PluginView::newStream(NPMIMEType type, const char* target, NPStream** stream)
+{
+ notImplemented();
+ // Unsupported
+ return NPERR_GENERIC_ERROR;
+}
+
+int32_t PluginView::write(NPStream* stream, int32_t len, void* buffer)
+{
+ notImplemented();
+ // Unsupported
+ return -1;
+}
+
+NPError PluginView::destroyStream(NPStream* stream, NPReason reason)
+{
+ if (!stream || PluginStream::ownerForStream(stream) != m_instance)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ PluginStream* browserStream = static_cast<PluginStream*>(stream->ndata);
+ browserStream->cancelAndDestroyStream(reason);
+
+ return NPERR_NO_ERROR;
+}
+
+void PluginView::status(const char* message)
+{
+ if (Page* page = m_parentFrame->page())
+ page->chrome()->setStatusbarText(m_parentFrame.get(), String::fromUTF8(message));
+}
+
+NPError PluginView::setValue(NPPVariable variable, void* value)
+{
+ LOG(Plugins, "PluginView::setValue(%s): ", prettyNameForNPPVariable(variable, value).data());
+
+ switch (variable) {
+ case NPPVpluginWindowBool:
+ m_isWindowed = value;
+ return NPERR_NO_ERROR;
+ case NPPVpluginTransparentBool:
+ m_isTransparent = value;
+ return NPERR_NO_ERROR;
+#if defined(XP_MACOSX)
+ case NPPVpluginDrawingModel: {
+ // Can only set drawing model inside NPP_New()
+ if (this != currentPluginView())
+ return NPERR_GENERIC_ERROR;
+
+ NPDrawingModel newDrawingModel = NPDrawingModel(uintptr_t(value));
+ switch (newDrawingModel) {
+ case NPDrawingModelCoreGraphics:
+ m_drawingModel = newDrawingModel;
+ return NPERR_NO_ERROR;
+#ifndef NP_NO_QUICKDRAW
+ case NPDrawingModelQuickDraw:
+#endif
+ case NPDrawingModelCoreAnimation:
+ default:
+ LOG(Plugins, "Plugin asked for unsupported drawing model: %s",
+ prettyNameForDrawingModel(newDrawingModel));
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+
+ case NPPVpluginEventModel: {
+ // Can only set event model inside NPP_New()
+ if (this != currentPluginView())
+ return NPERR_GENERIC_ERROR;
+
+ NPEventModel newEventModel = NPEventModel(uintptr_t(value));
+ switch (newEventModel) {
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon:
+#endif
+ case NPEventModelCocoa:
+ m_eventModel = newEventModel;
+ return NPERR_NO_ERROR;
+
+ default:
+ LOG(Plugins, "Plugin asked for unsupported event model: %s",
+ prettyNameForEventModel(newEventModel));
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+#endif // defined(XP_MACOSX)
+
+#if PLATFORM(QT) && defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
+ case NPPVpluginWindowlessLocalBool:
+ m_renderToImage = true;
+ return NPERR_NO_ERROR;
+#endif
+
+ default:
+#ifdef PLUGIN_PLATFORM_SETVALUE
+ return platformSetValue(variable, value);
+#else
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+#endif
+ }
+}
+
+void PluginView::invalidateTimerFired(Timer<PluginView>* timer)
+{
+ ASSERT(timer == &m_invalidateTimer);
+
+ for (unsigned i = 0; i < m_invalidRects.size(); i++)
+ invalidateRect(m_invalidRects[i]);
+ m_invalidRects.clear();
+}
+
+
+void PluginView::pushPopupsEnabledState(bool state)
+{
+ m_popupStateStack.append(state);
+}
+
+void PluginView::popPopupsEnabledState()
+{
+ m_popupStateStack.removeLast();
+}
+
+bool PluginView::arePopupsAllowed() const
+{
+ if (!m_popupStateStack.isEmpty())
+ return m_popupStateStack.last();
+
+ return false;
+}
+
+void PluginView::setJavaScriptPaused(bool paused)
+{
+ if (m_isJavaScriptPaused == paused)
+ return;
+ m_isJavaScriptPaused = paused;
+
+ if (m_isJavaScriptPaused)
+ m_requestTimer.stop();
+ else if (!m_requests.isEmpty())
+ m_requestTimer.startOneShot(0);
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+NPObject* PluginView::npObject()
+{
+ NPObject* object = 0;
+
+ if (!m_isStarted || !m_plugin || !m_plugin->pluginFuncs()->getvalue)
+ return 0;
+
+ // On Windows, calling Java's NPN_GetValue can allow the message loop to
+ // run, allowing loading to take place or JavaScript to run. Protect the
+ // PluginView from destruction. <rdar://problem/6978804>
+ RefPtr<PluginView> protect(this);
+
+ NPError npErr;
+ {
+ PluginView::setCurrentPluginView(this);
+#if USE(JSC)
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+#endif
+ setCallingPlugin(true);
+ npErr = m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginScriptableNPObject, &object);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ }
+
+ if (npErr != NPERR_NO_ERROR)
+ return 0;
+
+ return object;
+}
+#endif
+
+#if USE(JSC)
+PassRefPtr<JSC::Bindings::Instance> PluginView::bindingInstance()
+{
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ NPObject* object = npObject();
+ if (!object)
+ return 0;
+
+ if (hasOneRef()) {
+ // The renderer for the PluginView was destroyed during the above call, and
+ // the PluginView will be destroyed when this function returns, so we
+ // return null.
+ return 0;
+ }
+
+ RefPtr<JSC::Bindings::RootObject> root = m_parentFrame->script()->createRootObject(this);
+ RefPtr<JSC::Bindings::Instance> instance = JSC::Bindings::CInstance::create(object, root.release());
+
+ _NPN_ReleaseObject(object);
+
+ return instance.release();
+#else
+ return 0;
+#endif
+}
+#endif
+
+#if USE(V8)
+// This is really JS engine independent
+NPObject* PluginView::getNPObject() {
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ if (!m_plugin || !m_plugin->pluginFuncs()->getvalue)
+ return 0;
+
+ NPObject* object = 0;
+
+ NPError npErr;
+ {
+ PluginView::setCurrentPluginView(this);
+ setCallingPlugin(true);
+ npErr = m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginScriptableNPObject, &object);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ }
+
+ if (npErr != NPERR_NO_ERROR || !object)
+ return 0;
+
+ // Bindings::CInstance (used in JSC version) retains the object, so in ~PluginView() it calls
+ // cleanupScriptObjectsForPlugin() to releases the object. To maintain the reference count,
+ // don't call _NPN_ReleaseObject(object) here.
+ return object;
+#else
+ return 0;
+#endif // NETSCAPE_PLUGIN_API
+}
+#endif // V8
+
+void PluginView::disconnectStream(PluginStream* stream)
+{
+ ASSERT(m_streams.contains(stream));
+
+ m_streams.remove(stream);
+}
+
+void PluginView::setParameters(const Vector<String>& paramNames, const Vector<String>& paramValues)
+{
+ ASSERT(paramNames.size() == paramValues.size());
+
+ unsigned size = paramNames.size();
+ unsigned paramCount = 0;
+
+ m_paramNames = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size));
+ m_paramValues = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size));
+
+ for (unsigned i = 0; i < size; i++) {
+ if (m_plugin->quirks().contains(PluginQuirkRemoveWindowlessVideoParam) && equalIgnoringCase(paramNames[i], "windowlessvideo"))
+ continue;
+
+ if (paramNames[i] == "pluginspage")
+ m_pluginsPage = paramValues[i];
+
+ m_paramNames[paramCount] = createUTF8String(paramNames[i]);
+ m_paramValues[paramCount] = createUTF8String(paramValues[i]);
+
+ paramCount++;
+ }
+
+ m_paramCount = paramCount;
+}
+
+PluginView::PluginView(Frame* parentFrame, const IntSize& size, PluginPackage* plugin, Element* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
+ : m_parentFrame(parentFrame)
+ , m_plugin(plugin)
+ , m_element(element)
+ , m_isStarted(false)
+ , m_url(url)
+ , m_baseURL(m_parentFrame->loader()->completeURL(m_parentFrame->document()->baseURL().string()))
+ , m_status(PluginStatusLoadedSuccessfully)
+ , m_requestTimer(this, &PluginView::requestTimerFired)
+ , m_invalidateTimer(this, &PluginView::invalidateTimerFired)
+ , m_popPopupsStateTimer(this, &PluginView::popPopupsStateTimerFired)
+ , m_lifeSupportTimer(this, &PluginView::lifeSupportTimerFired)
+ , m_mode(loadManually ? NP_FULL : NP_EMBED)
+ , m_paramNames(0)
+ , m_paramValues(0)
+ , m_mimeType(mimeType)
+ , m_instance(0)
+#if defined(XP_MACOSX)
+ , m_isWindowed(false)
+#else
+ , m_isWindowed(true)
+#endif
+ , m_isTransparent(false)
+ , m_haveInitialized(false)
+ , m_isWaitingToStart(false)
+#if defined(XP_UNIX)
+ , m_needsXEmbed(false)
+#endif
+#if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
+ , m_pluginWndProc(0)
+ , m_lastMessage(0)
+ , m_isCallingPluginWndProc(false)
+ , m_wmPrintHDC(0)
+ , m_haveUpdatedPluginWidget(false)
+#endif
+#if (PLATFORM(QT) && OS(WINDOWS)) || defined(XP_MACOSX)
+ , m_window(0)
+#endif
+#if defined(XP_MACOSX)
+ , m_drawingModel(NPDrawingModel(-1))
+ , m_eventModel(NPEventModel(-1))
+ , m_contextRef(0)
+ , m_fakeWindow(0)
+#endif
+#if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
+ , m_hasPendingGeometryChange(true)
+ , m_drawable(0)
+ , m_visual(0)
+ , m_colormap(0)
+ , m_pluginDisplay(0)
+#endif
+#if PLATFORM(QT) && defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
+ , m_renderToImage(false)
+#endif
+ , m_loadManually(loadManually)
+ , m_manualStream(0)
+ , m_isJavaScriptPaused(false)
+ , m_isHalted(false)
+ , m_hasBeenHalted(false)
+ , m_haveCalledSetWindow(false)
+{
+#if defined(ANDROID_PLUGINS)
+ platformInit();
+#endif
+
+ if (!m_plugin) {
+ m_status = PluginStatusCanNotFindPlugin;
+ return;
+ }
+
+ m_instance = &m_instanceStruct;
+ m_instance->ndata = this;
+ m_instance->pdata = 0;
+
+ instanceMap().add(m_instance, this);
+
+ setParameters(paramNames, paramValues);
+
+ memset(&m_npWindow, 0, sizeof(m_npWindow));
+#if defined(XP_MACOSX)
+ memset(&m_npCgContext, 0, sizeof(m_npCgContext));
+#endif
+
+ resize(size);
+}
+
+void PluginView::focusPluginElement()
+{
+ // Focus the plugin
+ if (Page* page = m_parentFrame->page())
+ page->focusController()->setFocusedFrame(m_parentFrame);
+ m_parentFrame->document()->setFocusedNode(m_element);
+}
+
+void PluginView::didReceiveResponse(const ResourceResponse& response)
+{
+ if (m_status != PluginStatusLoadedSuccessfully)
+ return;
+
+ ASSERT(m_loadManually);
+ ASSERT(!m_manualStream);
+
+ m_manualStream = PluginStream::create(this, m_parentFrame.get(), m_parentFrame->loader()->activeDocumentLoader()->request(), false, 0, plugin()->pluginFuncs(), instance(), m_plugin->quirks());
+ m_manualStream->setLoadManually(true);
+
+ m_manualStream->didReceiveResponse(0, response);
+}
+
+void PluginView::didReceiveData(const char* data, int length)
+{
+ if (m_status != PluginStatusLoadedSuccessfully)
+ return;
+
+ ASSERT(m_loadManually);
+ ASSERT(m_manualStream);
+
+ m_manualStream->didReceiveData(0, data, length);
+}
+
+void PluginView::didFinishLoading()
+{
+ if (m_status != PluginStatusLoadedSuccessfully)
+ return;
+
+ ASSERT(m_loadManually);
+ ASSERT(m_manualStream);
+
+ m_manualStream->didFinishLoading(0);
+}
+
+void PluginView::didFail(const ResourceError& error)
+{
+ if (m_status != PluginStatusLoadedSuccessfully)
+ return;
+
+ ASSERT(m_loadManually);
+ ASSERT(m_manualStream);
+
+ m_manualStream->didFail(0, error);
+}
+
+void PluginView::setCallingPlugin(bool b) const
+{
+ if (!m_plugin->quirks().contains(PluginQuirkHasModalMessageLoop))
+ return;
+
+ if (b)
+ ++s_callingPlugin;
+ else
+ --s_callingPlugin;
+
+ ASSERT(s_callingPlugin >= 0);
+}
+
+bool PluginView::isCallingPlugin()
+{
+ return s_callingPlugin > 0;
+}
+
+PassRefPtr<PluginView> PluginView::create(Frame* parentFrame, const IntSize& size, Element* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
+{
+ // if we fail to find a plugin for this MIME type, findPlugin will search for
+ // a plugin by the file extension and update the MIME type, so pass a mutable String
+ String mimeTypeCopy = mimeType;
+ PluginPackage* plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
+
+ // No plugin was found, try refreshing the database and searching again
+ if (!plugin && PluginDatabase::installedPlugins()->refresh()) {
+ mimeTypeCopy = mimeType;
+ plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
+ }
+
+ return adoptRef(new PluginView(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually));
+}
+
+void PluginView::freeStringArray(char** stringArray, int length)
+{
+ if (!stringArray)
+ return;
+
+ for (int i = 0; i < length; i++)
+ fastFree(stringArray[i]);
+
+ fastFree(stringArray);
+}
+
+static inline bool startsWithBlankLine(const Vector<char>& buffer)
+{
+ return buffer.size() > 0 && buffer[0] == '\n';
+}
+
+static inline int locationAfterFirstBlankLine(const Vector<char>& buffer)
+{
+ const char* bytes = buffer.data();
+ unsigned length = buffer.size();
+
+ for (unsigned i = 0; i < length - 4; i++) {
+ // Support for Acrobat. It sends "\n\n".
+ if (bytes[i] == '\n' && bytes[i + 1] == '\n')
+ return i + 2;
+
+ // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
+ if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
+ i += 2;
+ if (i == 2)
+ return i;
+ else if (bytes[i] == '\n')
+ // Support for Director. It sends "\r\n\n" (3880387).
+ return i + 1;
+ else if (bytes[i] == '\r' && bytes[i + 1] == '\n')
+ // Support for Flash. It sends "\r\n\r\n" (3758113).
+ return i + 2;
+ }
+ }
+
+ return -1;
+}
+
+static inline const char* findEOL(const char* bytes, unsigned length)
+{
+ // According to the HTTP specification EOL is defined as
+ // a CRLF pair. Unfortunately, some servers will use LF
+ // instead. Worse yet, some servers will use a combination
+ // of both (e.g. <header>CRLFLF<body>), so findEOL needs
+ // to be more forgiving. It will now accept CRLF, LF or
+ // CR.
+ //
+ // It returns NULL if EOLF is not found or it will return
+ // a pointer to the first terminating character.
+ for (unsigned i = 0; i < length; i++) {
+ if (bytes[i] == '\n')
+ return bytes + i;
+ if (bytes[i] == '\r') {
+ // Check to see if spanning buffer bounds
+ // (CRLF is across reads). If so, wait for
+ // next read.
+ if (i + 1 == length)
+ break;
+
+ return bytes + i;
+ }
+ }
+
+ return 0;
+}
+
+static inline String capitalizeRFC822HeaderFieldName(const String& name)
+{
+ bool capitalizeCharacter = true;
+ String result;
+
+ for (unsigned i = 0; i < name.length(); i++) {
+ UChar c;
+
+ if (capitalizeCharacter && name[i] >= 'a' && name[i] <= 'z')
+ c = toASCIIUpper(name[i]);
+ else if (!capitalizeCharacter && name[i] >= 'A' && name[i] <= 'Z')
+ c = toASCIILower(name[i]);
+ else
+ c = name[i];
+
+ if (name[i] == '-')
+ capitalizeCharacter = true;
+ else
+ capitalizeCharacter = false;
+
+ result.append(c);
+ }
+
+ return result;
+}
+
+static inline HTTPHeaderMap parseRFC822HeaderFields(const Vector<char>& buffer, unsigned length)
+{
+ const char* bytes = buffer.data();
+ const char* eol;
+ String lastKey;
+ HTTPHeaderMap headerFields;
+
+ // Loop ove rlines until we're past the header, or we can't find any more end-of-lines
+ while ((eol = findEOL(bytes, length))) {
+ const char* line = bytes;
+ int lineLength = eol - bytes;
+
+ // Move bytes to the character after the terminator as returned by findEOL.
+ bytes = eol + 1;
+ if ((*eol == '\r') && (*bytes == '\n'))
+ bytes++; // Safe since findEOL won't return a spanning CRLF.
+
+ length -= (bytes - line);
+ if (lineLength == 0)
+ // Blank line; we're at the end of the header
+ break;
+ else if (*line == ' ' || *line == '\t') {
+ // Continuation of the previous header
+ if (lastKey.isNull()) {
+ // malformed header; ignore it and continue
+ continue;
+ } else {
+ // Merge the continuation of the previous header
+ String currentValue = headerFields.get(lastKey);
+ String newValue(line, lineLength);
+
+ headerFields.set(lastKey, currentValue + newValue);
+ }
+ } else {
+ // Brand new header
+ const char* colon;
+ for (colon = line; *colon != ':' && colon != eol; colon++) {
+ // empty loop
+ }
+ if (colon == eol)
+ // malformed header; ignore it and continue
+ continue;
+ else {
+ lastKey = capitalizeRFC822HeaderFieldName(String(line, colon - line));
+ String value;
+
+ for (colon++; colon != eol; colon++) {
+ if (*colon != ' ' && *colon != '\t')
+ break;
+ }
+ if (colon == eol)
+ value = "";
+ else
+ value = String(colon, eol - colon);
+
+ String oldValue = headerFields.get(lastKey);
+ if (!oldValue.isNull()) {
+ String tmp = oldValue;
+ tmp += ", ";
+ tmp += value;
+ value = tmp;
+ }
+
+ headerFields.set(lastKey, value);
+ }
+ }
+ }
+
+ return headerFields;
+}
+
+NPError PluginView::handlePost(const char* url, const char* target, uint32_t len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders)
+{
+ if (!url || !len || !buf)
+ return NPERR_INVALID_PARAM;
+
+ FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin());
+
+ HTTPHeaderMap headerFields;
+ Vector<char> buffer;
+
+ if (file) {
+ NPError readResult = handlePostReadFile(buffer, len, buf);
+ if(readResult != NPERR_NO_ERROR)
+ return readResult;
+ } else {
+ buffer.resize(len);
+ memcpy(buffer.data(), buf, len);
+ }
+
+ const char* postData = buffer.data();
+ int postDataLength = buffer.size();
+
+ if (allowHeaders) {
+ if (startsWithBlankLine(buffer)) {
+ postData++;
+ postDataLength--;
+ } else {
+ int location = locationAfterFirstBlankLine(buffer);
+ if (location != -1) {
+ // If the blank line is somewhere in the middle of the buffer, everything before is the header
+ headerFields = parseRFC822HeaderFields(buffer, location);
+ unsigned dataLength = buffer.size() - location;
+
+ // Sometimes plugins like to set Content-Length themselves when they post,
+ // but WebFoundation does not like that. So we will remove the header
+ // and instead truncate the data to the requested length.
+ String contentLength = headerFields.get("Content-Length");
+
+ if (!contentLength.isNull())
+ dataLength = min(contentLength.toInt(), (int)dataLength);
+ headerFields.remove("Content-Length");
+
+ postData += location;
+ postDataLength = dataLength;
+ }
+ }
+ }
+
+ frameLoadRequest.resourceRequest().setHTTPMethod("POST");
+ frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url));
+ frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields);
+ frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(postData, postDataLength));
+ frameLoadRequest.setFrameName(target);
+
+ return load(frameLoadRequest, sendNotification, notifyData);
+}
+
+#ifdef PLUGIN_SCHEDULE_TIMER
+uint32_t PluginView::scheduleTimer(NPP instance, uint32_t interval, bool repeat,
+ void (*timerFunc)(NPP, uint32_t timerID))
+{
+ return m_timerList.schedule(instance, interval, repeat, timerFunc);
+}
+
+void PluginView::unscheduleTimer(NPP instance, uint32_t timerID)
+{
+ m_timerList.unschedule(instance, timerID);
+}
+#endif
+
+void PluginView::invalidateWindowlessPluginRect(const IntRect& rect)
+{
+ if (!isVisible())
+ return;
+
+ if (!m_element->renderer())
+ return;
+ RenderBox* renderer = toRenderBox(m_element->renderer());
+
+ IntRect dirtyRect = rect;
+ dirtyRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop());
+ renderer->repaintRectangle(dirtyRect);
+}
+
+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(), ColorSpaceDeviceRGB, imageRect.location());
+ context->restore();
+}
+
+static const char* MozillaUserAgent = "Mozilla/5.0 ("
+#if defined(XP_MACOSX)
+ "Macintosh; U; Intel Mac OS X;"
+#elif defined(XP_WIN)
+ "Windows; U; Windows NT 5.1;"
+#elif defined(XP_UNIX)
+// The Gtk port uses X11 plugins in Mac.
+#if OS(DARWIN) && PLATFORM(GTK)
+ "X11; U; Intel Mac OS X;"
+#else
+ "X11; U; Linux i686;"
+#endif
+#endif
+ " en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
+
+const char* PluginView::userAgent()
+{
+#if !PLATFORM(ANDROID)
+ if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent))
+ return MozillaUserAgent;
+#endif
+
+ if (m_userAgent.isNull())
+ m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8();
+
+ return m_userAgent.data();
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+const char* PluginView::userAgentStatic()
+{
+ return MozillaUserAgent;
+}
+#endif
+
+
+Node* PluginView::node() const
+{
+ return m_element;
+}
+
+String PluginView::pluginName() const
+{
+ return m_plugin->name();
+}
+
+void PluginView::lifeSupportTimerFired(Timer<PluginView>*)
+{
+ deref();
+}
+
+void PluginView::keepAlive()
+{
+ if (m_lifeSupportTimer.isActive())
+ return;
+
+ ref();
+ m_lifeSupportTimer.startOneShot(0);
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+void PluginView::keepAlive(NPP instance)
+{
+ PluginView* view = instanceMap().get(instance);
+ if (!view)
+ return;
+
+ view->keepAlive();
+}
+
+NPError PluginView::getValueStatic(NPNVariable variable, void* value)
+{
+ LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data());
+
+ NPError result;
+ if (platformGetValueStatic(variable, value, &result))
+ return result;
+
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError PluginView::getValue(NPNVariable variable, void* value)
+{
+ LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data());
+
+ NPError result;
+ if (platformGetValue(variable, value, &result))
+ return result;
+
+ if (platformGetValueStatic(variable, value, &result))
+ return result;
+
+ switch (variable) {
+ 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;
+ }
+
+ case NPNVprivateModeBool: {
+ Page* page = m_parentFrame->page();
+ if (!page)
+ return NPERR_GENERIC_ERROR;
+ *((NPBool*)value) = !page->settings() || page->settings()->privateBrowsingEnabled();
+ return NPERR_NO_ERROR;
+ }
+
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+static Frame* getFrame(Frame* parentFrame, Element* element)
+{
+ if (parentFrame)
+ return parentFrame;
+
+ Document* document = element->document();
+ if (!document)
+ document = element->ownerDocument();
+ if (document)
+ return document->frame();
+
+ return 0;
+}
+
+NPError PluginView::getValueForURL(NPNURLVariable variable, const char* url, char** value, uint32_t* len)
+{
+ LOG(Plugins, "PluginView::getValueForURL(%s)", prettyNameForNPNURLVariable(variable).data());
+
+ NPError result = NPERR_NO_ERROR;
+
+ switch (variable) {
+ case NPNURLVCookie: {
+ KURL u(m_baseURL, url);
+ if (u.isValid()) {
+ Frame* frame = getFrame(parentFrame(), m_element);
+ if (frame) {
+ const CString cookieStr = cookies(frame->document(), u).utf8();
+ if (!cookieStr.isNull()) {
+ const int size = cookieStr.length();
+ *value = static_cast<char*>(NPN_MemAlloc(size+1));
+ if (*value) {
+ memset(*value, 0, size+1);
+ memcpy(*value, cookieStr.data(), size+1);
+ if (len)
+ *len = size;
+ } else
+ result = NPERR_OUT_OF_MEMORY_ERROR;
+ }
+ }
+ } else
+ result = NPERR_INVALID_URL;
+ break;
+ }
+ case NPNURLVProxy: {
+ KURL u(m_baseURL, url);
+ if (u.isValid()) {
+ Frame* frame = getFrame(parentFrame(), m_element);
+ const FrameLoader* frameLoader = frame ? frame->loader() : 0;
+ const NetworkingContext* context = frameLoader ? frameLoader->networkingContext() : 0;
+ const CString proxyStr = toString(proxyServersForURL(u, context)).utf8();
+ if (!proxyStr.isNull()) {
+ const int size = proxyStr.length();
+ *value = static_cast<char*>(NPN_MemAlloc(size+1));
+ if (*value) {
+ memset(*value, 0, size+1);
+ memcpy(*value, proxyStr.data(), size+1);
+ if (len)
+ *len = size;
+ } else
+ result = NPERR_OUT_OF_MEMORY_ERROR;
+ }
+ } else
+ result = NPERR_INVALID_URL;
+ break;
+ }
+ default:
+ result = NPERR_GENERIC_ERROR;
+ LOG(Plugins, "PluginView::getValueForURL: %s", prettyNameForNPNURLVariable(variable).data());
+ break;
+ }
+
+ return result;
+}
+
+
+NPError PluginView::setValueForURL(NPNURLVariable variable, const char* url, const char* value, uint32_t len)
+{
+ LOG(Plugins, "PluginView::setValueForURL(%s)", prettyNameForNPNURLVariable(variable).data());
+
+ NPError result = NPERR_NO_ERROR;
+
+ switch (variable) {
+ case NPNURLVCookie: {
+ KURL u(m_baseURL, url);
+ if (u.isValid()) {
+ const String cookieStr = String::fromUTF8(value, len);
+ Frame* frame = getFrame(parentFrame(), m_element);
+ if (frame && !cookieStr.isEmpty())
+ setCookies(frame->document(), u, cookieStr);
+ } else
+ result = NPERR_INVALID_URL;
+ break;
+ }
+ case NPNURLVProxy:
+ LOG(Plugins, "PluginView::setValueForURL(%s): Plugins are NOT allowed to set proxy information.", prettyNameForNPNURLVariable(variable).data());
+ result = NPERR_GENERIC_ERROR;
+ break;
+ default:
+ LOG(Plugins, "PluginView::setValueForURL: %s", prettyNameForNPNURLVariable(variable).data());
+ result = NPERR_GENERIC_ERROR;
+ break;
+ }
+
+ return result;
+}
+
+NPError PluginView::getAuthenticationInfo(const char* protocol, const char* host, int32_t port, const char* scheme, const char* realm, char** username, uint32_t* ulen, char** password, uint32_t* plen)
+{
+ LOG(Plugins, "PluginView::getAuthenticationInfo: protocol=%s, host=%s, port=%d", protocol, host, port);
+ notImplemented();
+ return NPERR_GENERIC_ERROR;
+}
+#endif
+
+void PluginView::privateBrowsingStateChanged(bool privateBrowsingEnabled)
+{
+ NPP_SetValueProcPtr setValue = m_plugin->pluginFuncs()->setvalue;
+ if (!setValue)
+ return;
+
+ PluginView::setCurrentPluginView(this);
+#if USE(JSC)
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+#endif
+ setCallingPlugin(true);
+ NPBool value = privateBrowsingEnabled;
+ setValue(m_instance, NPNVprivateModeBool, &value);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(NETSCAPE_PLUGIN_API)
diff --git a/Source/WebCore/plugins/PluginView.h b/Source/WebCore/plugins/PluginView.h
new file mode 100644
index 0000000..a58d217
--- /dev/null
+++ b/Source/WebCore/plugins/PluginView.h
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginView_h
+#define PluginView_h
+
+#include "FrameLoadRequest.h"
+#include "HaltablePlugin.h"
+#include "IntRect.h"
+#include "MediaCanStartListener.h"
+#include "PluginViewBase.h"
+#include "ResourceRequest.h"
+#include "Timer.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+#include "PluginStream.h"
+#include "npruntime_internal.h"
+#endif
+
+// ANDROID
+// TODO: Upstream to webkit.org
+#ifdef PLUGIN_SCHEDULE_TIMER
+#include "PluginTimer.h"
+#endif
+
+#if OS(WINDOWS) && (PLATFORM(QT) || PLATFORM(WX))
+typedef struct HWND__* HWND;
+typedef HWND PlatformPluginWidget;
+#elif defined(ANDROID_PLUGINS)
+typedef struct PluginWidgetAndroid* PlatformPluginWidget;
+#else
+typedef PlatformWidget PlatformPluginWidget;
+#if defined(XP_MACOSX) && PLATFORM(QT)
+#include <QPixmap>
+#endif
+#endif
+#if PLATFORM(QT)
+#include <QGraphicsItem>
+#include <QImage>
+QT_BEGIN_NAMESPACE
+class QPainter;
+QT_END_NAMESPACE
+#endif
+
+#if USE(JSC)
+namespace JSC {
+ namespace Bindings {
+ class Instance;
+ }
+}
+#endif
+
+class NPObject;
+
+namespace WebCore {
+ class Element;
+ class Frame;
+ class Image;
+ class KeyboardEvent;
+ class MouseEvent;
+#ifdef ANDROID_PLUGINS
+ class TouchEvent;
+#endif
+ class KURL;
+#if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
+ class PluginMessageThrottlerWin;
+#endif
+ class PluginPackage;
+ class PluginRequest;
+ class PluginStream;
+ class ResourceError;
+ class ResourceResponse;
+
+ enum PluginStatus {
+ PluginStatusCanNotFindPlugin,
+ PluginStatusCanNotLoadPlugin,
+ PluginStatusLoadedSuccessfully
+ };
+
+ class PluginRequest : public Noncopyable {
+ public:
+ PluginRequest(const FrameLoadRequest& frameLoadRequest, bool sendNotification, void* notifyData, bool shouldAllowPopups)
+ : m_frameLoadRequest(frameLoadRequest)
+ , m_notifyData(notifyData)
+ , m_sendNotification(sendNotification)
+ , m_shouldAllowPopups(shouldAllowPopups) { }
+ public:
+ const FrameLoadRequest& frameLoadRequest() const { return m_frameLoadRequest; }
+ void* notifyData() const { return m_notifyData; }
+ bool sendNotification() const { return m_sendNotification; }
+ bool shouldAllowPopups() const { return m_shouldAllowPopups; }
+ private:
+ FrameLoadRequest m_frameLoadRequest;
+ void* m_notifyData;
+ bool m_sendNotification;
+ bool m_shouldAllowPopups;
+ };
+
+ class PluginManualLoader {
+ public:
+ virtual ~PluginManualLoader() {}
+ virtual void didReceiveResponse(const ResourceResponse&) = 0;
+ virtual void didReceiveData(const char*, int) = 0;
+ virtual void didFinishLoading() = 0;
+ virtual void didFail(const ResourceError&) = 0;
+ };
+
+ class PluginView : public PluginViewBase
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ , private PluginStreamClient
+#endif
+ , public PluginManualLoader
+ , private HaltablePlugin
+ , private MediaCanStartListener {
+ public:
+ static PassRefPtr<PluginView> create(Frame* parentFrame, const IntSize&, Element*, const KURL&, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually);
+ virtual ~PluginView();
+
+ PluginPackage* plugin() const { return m_plugin.get(); }
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ NPP instance() const { return m_instance; }
+#endif
+
+ void setNPWindowRect(const IntRect&);
+ static PluginView* currentPluginView();
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ NPObject* npObject();
+#endif
+#if USE(JSC)
+ PassRefPtr<JSC::Bindings::Instance> bindingInstance();
+#endif
+
+ PluginStatus status() const { return m_status; }
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ // NPN functions
+ NPError getURLNotify(const char* url, const char* target, void* notifyData);
+ NPError getURL(const char* url, const char* target);
+ NPError postURLNotify(const char* url, const char* target, uint32_t len, const char* but, NPBool file, void* notifyData);
+ NPError postURL(const char* url, const char* target, uint32_t len, const char* but, NPBool file);
+ NPError newStream(NPMIMEType type, const char* target, NPStream** stream);
+ int32_t write(NPStream* stream, int32_t len, void* buffer);
+ NPError destroyStream(NPStream* stream, NPReason reason);
+#endif
+ const char* userAgent();
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ static const char* userAgentStatic();
+#endif
+ void status(const char* message);
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ NPError getValue(NPNVariable variable, void* value);
+ static NPError getValueStatic(NPNVariable variable, void* value);
+ NPError setValue(NPPVariable variable, void* value);
+ NPError getValueForURL(NPNURLVariable variable, const char* url, char** value, uint32_t* len);
+ NPError setValueForURL(NPNURLVariable variable, const char* url, const char* value, uint32_t len);
+ NPError getAuthenticationInfo(const char* protocol, const char* host, int32_t port, const char* scheme, const char* realm, char** username, uint32_t* ulen, char** password, uint32_t* plen);
+ void invalidateRect(NPRect*);
+ void invalidateRegion(NPRegion);
+#endif
+ void forceRedraw();
+ void pushPopupsEnabledState(bool state);
+ void popPopupsEnabledState();
+#ifdef PLUGIN_SCHEDULE_TIMER
+ uint32_t scheduleTimer(NPP, uint32_t interval, bool repeat,
+ void (*timerFunc)(NPP, uint32_t timerID));
+ void unscheduleTimer(NPP, uint32_t timerID);
+#endif
+#if USE(V8)
+ NPObject* getNPObject();
+#endif
+
+ virtual void invalidateRect(const IntRect&);
+
+ bool arePopupsAllowed() const;
+
+ void setJavaScriptPaused(bool);
+
+ void privateBrowsingStateChanged(bool);
+
+ void disconnectStream(PluginStream*);
+ void streamDidFinishLoading(PluginStream* stream) { disconnectStream(stream); }
+
+ // Widget functions
+ virtual void setFrameRect(const IntRect&);
+ virtual void frameRectsChanged();
+ virtual void setFocus(bool);
+ virtual void show();
+ virtual void hide();
+ virtual void paint(GraphicsContext*, const IntRect&);
+
+ // This method is used by plugins on all platforms to obtain a clip rect that includes clips set by WebCore,
+ // e.g., in overflow:auto sections. The clip rects coordinates are in the containing window's coordinate space.
+ // This clip includes any clips that the widget itself sets up for its children.
+ IntRect windowClipRect() const;
+
+ virtual void handleEvent(Event*);
+ virtual void setParent(ScrollView*);
+ virtual void setParentVisible(bool);
+
+ virtual bool isPluginView() const { return true; }
+
+ Frame* parentFrame() const { return m_parentFrame.get(); }
+
+ void focusPluginElement();
+
+ const String& pluginsPage() const { return m_pluginsPage; }
+ const String& mimeType() const { return m_mimeType; }
+ const KURL& url() const { return m_url; }
+
+#if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
+ static LRESULT CALLBACK PluginViewWndProc(HWND, UINT, WPARAM, LPARAM);
+ LRESULT wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ WNDPROC pluginWndProc() const { return m_pluginWndProc; }
+#endif
+
+ // Used for manual loading
+ void didReceiveResponse(const ResourceResponse&);
+ void didReceiveData(const char*, int);
+ void didFinishLoading();
+ void didFail(const ResourceError&);
+
+ // HaltablePlugin
+ virtual void halt();
+ virtual void restart();
+ virtual Node* node() const;
+ virtual bool isWindowed() const { return m_isWindowed; }
+ virtual String pluginName() const;
+
+ bool isHalted() const { return m_isHalted; }
+ bool hasBeenHalted() const { return m_hasBeenHalted; }
+
+ static bool isCallingPlugin();
+
+#ifdef ANDROID_PLUGINS
+ Element* getElement() const { return m_element; }
+#endif
+
+ bool start();
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ static void keepAlive(NPP);
+#endif
+ void keepAlive();
+
+#if USE(ACCELERATED_COMPOSITING)
+#if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API) && PLATFORM(QT)
+ virtual PlatformLayer* platformLayer() const;
+#elif ENABLE(NETSCAPE_PLUGIN_API) && defined(ANDROID_PLUGINS)
+ virtual PlatformLayer* platformLayer() const;
+#else
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
+#endif
+
+ private:
+ PluginView(Frame* parentFrame, const IntSize&, PluginPackage*, Element*, const KURL&, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually);
+
+ void setParameters(const Vector<String>& paramNames, const Vector<String>& paramValues);
+ bool startOrAddToUnstartedList();
+ void init();
+ bool platformStart();
+ void stop();
+ void platformDestroy();
+ static void setCurrentPluginView(PluginView*);
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ NPError load(const FrameLoadRequest&, bool sendNotification, void* notifyData);
+ NPError handlePost(const char* url, const char* target, uint32_t len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders);
+ NPError handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf);
+#endif
+ static void freeStringArray(char** stringArray, int length);
+ void setCallingPlugin(bool) const;
+
+ void invalidateWindowlessPluginRect(const IntRect&);
+
+ virtual void mediaCanStart();
+
+#if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
+ void paintWindowedPluginIntoContext(GraphicsContext*, const IntRect&);
+ static HDC WINAPI hookedBeginPaint(HWND, PAINTSTRUCT*);
+ static BOOL WINAPI hookedEndPaint(HWND, const PAINTSTRUCT*);
+#endif
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ static bool platformGetValueStatic(NPNVariable variable, void* value, NPError* result);
+ bool platformGetValue(NPNVariable variable, void* value, NPError* result);
+#endif
+
+ RefPtr<Frame> m_parentFrame;
+ RefPtr<PluginPackage> m_plugin;
+ Element* m_element;
+ bool m_isStarted;
+ KURL m_url;
+ KURL m_baseURL;
+ PluginStatus m_status;
+ Vector<IntRect> m_invalidRects;
+
+ void performRequest(PluginRequest*);
+ void scheduleRequest(PluginRequest*);
+ void requestTimerFired(Timer<PluginView>*);
+ void invalidateTimerFired(Timer<PluginView>*);
+ Timer<PluginView> m_requestTimer;
+ Timer<PluginView> m_invalidateTimer;
+
+ void popPopupsStateTimerFired(Timer<PluginView>*);
+ Timer<PluginView> m_popPopupsStateTimer;
+
+ void lifeSupportTimerFired(Timer<PluginView>*);
+ Timer<PluginView> m_lifeSupportTimer;
+
+#ifndef NP_NO_CARBON
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ bool dispatchNPEvent(NPEvent&);
+#endif // ENABLE(NETSCAPE_PLUGIN_API)
+#endif
+ void updatePluginWidget();
+ void paintMissingPluginIcon(GraphicsContext*, const IntRect&);
+
+ void handleKeyboardEvent(KeyboardEvent*);
+ void handleMouseEvent(MouseEvent*);
+#if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
+ void handleFocusInEvent();
+ void handleFocusOutEvent();
+#endif
+
+#if OS(WINDOWS)
+ void paintIntoTransformedContext(HDC);
+ PassRefPtr<Image> snapshot();
+#endif
+
+#ifdef ANDROID_PLUGINS
+ void handleFocusEvent(bool hasFocus);
+ void handleTouchEvent(TouchEvent*);
+ // called at the end of the base constructor
+ void platformInit();
+#endif
+#ifdef PLUGIN_PLATFORM_SETVALUE
+ // called if the default setValue does not recognize the variable
+ NPError platformSetValue(NPPVariable variable, void* value);
+#endif
+
+ int m_mode;
+ int m_paramCount;
+ char** m_paramNames;
+ char** m_paramValues;
+ String m_pluginsPage;
+
+ String m_mimeType;
+ WTF::CString m_userAgent;
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ NPP m_instance;
+ NPP_t m_instanceStruct;
+ NPWindow m_npWindow;
+#endif
+
+ Vector<bool, 4> m_popupStateStack;
+
+ HashSet<RefPtr<PluginStream> > m_streams;
+ Vector<PluginRequest*> m_requests;
+
+ bool m_isWindowed;
+ bool m_isTransparent;
+ bool m_haveInitialized;
+ bool m_isWaitingToStart;
+
+#if defined(XP_UNIX)
+ bool m_needsXEmbed;
+#endif
+
+#if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
+ OwnPtr<PluginMessageThrottlerWin> m_messageThrottler;
+ WNDPROC m_pluginWndProc;
+ unsigned m_lastMessage;
+ bool m_isCallingPluginWndProc;
+ HDC m_wmPrintHDC;
+ bool m_haveUpdatedPluginWidget;
+#endif
+
+// ANDROID
+// TODO: Upstream to webkit.org
+#ifdef PLUGIN_SCHEDULE_TIMER
+ PluginTimerList m_timerList;
+#endif
+
+#if ((PLATFORM(QT) || PLATFORM(WX)) && OS(WINDOWS)) || defined(XP_MACOSX)
+ // On Mac OSX and Qt/Windows the plugin does not have its own native widget,
+ // but is using the containing window as its reference for positioning/painting.
+ PlatformPluginWidget m_window;
+public:
+ PlatformPluginWidget platformPluginWidget() const { return m_window; }
+ void setPlatformPluginWidget(PlatformPluginWidget widget) { m_window = widget; }
+#elif defined(ANDROID_PLUGINS)
+public:
+ PlatformPluginWidget m_window;
+ PlatformPluginWidget platformPluginWidget() const { return m_window; } // MANUAL MERGE FIXME
+#else
+public:
+ void setPlatformPluginWidget(PlatformPluginWidget widget) { setPlatformWidget(widget); }
+ PlatformPluginWidget platformPluginWidget() const { return platformWidget(); }
+#endif
+
+private:
+
+#if defined(XP_UNIX) || OS(SYMBIAN) || defined(ANDROID_PLUGINS)
+ void setNPWindowIfNeeded();
+#elif defined(XP_MACOSX)
+ NP_CGContext m_npCgContext;
+ OwnPtr<Timer<PluginView> > m_nullEventTimer;
+ NPDrawingModel m_drawingModel;
+ NPEventModel m_eventModel;
+ CGContextRef m_contextRef;
+ WindowRef m_fakeWindow;
+#if PLATFORM(QT)
+ QPixmap m_pixmap;
+#endif
+
+ Point m_lastMousePos;
+ void setNPWindowIfNeeded();
+ void nullEventTimerFired(Timer<PluginView>*);
+ Point globalMousePosForPlugin() const;
+ Point mousePosForPlugin(MouseEvent* event = 0) const;
+#endif
+
+#if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
+ bool m_hasPendingGeometryChange;
+ Pixmap m_drawable;
+ Visual* m_visual;
+ Colormap m_colormap;
+ Display* m_pluginDisplay;
+
+ void initXEvent(XEvent* event);
+#endif
+
+#if PLATFORM(QT)
+#if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
+ QImage m_image;
+ bool m_renderToImage;
+ void paintUsingImageSurfaceExtension(QPainter* painter, const IntRect& exposedRect);
+#endif
+#if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
+ void paintUsingXPixmap(QPainter* painter, const QRect &exposedRect);
+#if USE(ACCELERATED_COMPOSITING)
+ OwnPtr<PlatformLayer> m_platformLayer;
+ friend class PluginGraphicsLayerQt;
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif
+#endif // PLATFORM(QT)
+
+ IntRect m_clipRect; // The clip rect to apply to a windowed plug-in
+ IntRect m_windowRect; // Our window rect.
+#ifdef ANDROID_PLUGINS
+ IntRect m_pageRect; // The rect in page coordinate system.
+#endif
+
+ bool m_loadManually;
+ RefPtr<PluginStream> m_manualStream;
+
+ bool m_isJavaScriptPaused;
+
+ bool m_isHalted;
+ bool m_hasBeenHalted;
+
+ bool m_haveCalledSetWindow;
+
+ static PluginView* s_currentPluginView;
+ };
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/plugins/PluginViewBase.h b/Source/WebCore/plugins/PluginViewBase.h
new file mode 100644
index 0000000..8dc667a
--- /dev/null
+++ b/Source/WebCore/plugins/PluginViewBase.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginWidget_h
+#define PluginWidget_h
+
+#include "Widget.h"
+#include "GraphicsLayer.h"
+
+namespace JSC {
+ class ExecState;
+ class JSGlobalObject;
+ class JSObject;
+}
+
+namespace WebCore {
+
+// PluginViewBase is a widget that all plug-in views inherit from, both in Webkit and WebKit2.
+// It's intended as a stopgap measure until we can merge all plug-in views into a single plug-in view.
+class PluginViewBase : public Widget {
+public:
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
+
+ virtual JSC::JSObject* scriptObject(JSC::JSGlobalObject*) { return 0; }
+ virtual void privateBrowsingStateChanged(bool) { }
+
+protected:
+ PluginViewBase(PlatformWidget widget = 0) : Widget(widget) { }
+
+private:
+ virtual bool isPluginViewBase() const { return true; }
+};
+
+} // namespace WebCore
+
+#endif // PluginWidget_h
diff --git a/Source/WebCore/plugins/PluginViewNone.cpp b/Source/WebCore/plugins/PluginViewNone.cpp
new file mode 100644
index 0000000..9aeaf3b
--- /dev/null
+++ b/Source/WebCore/plugins/PluginViewNone.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> 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 "PluginView.h"
+
+#if USE(JSC)
+#include "Bridge.h"
+#endif
+
+using namespace WTF;
+
+namespace WebCore {
+
+void PluginView::setFocus(bool)
+{
+}
+
+void PluginView::show()
+{
+}
+
+void PluginView::hide()
+{
+}
+
+void PluginView::paint(GraphicsContext*, const IntRect&)
+{
+}
+
+void PluginView::handleKeyboardEvent(KeyboardEvent*)
+{
+}
+
+void PluginView::handleMouseEvent(MouseEvent*)
+{
+}
+
+void PluginView::setParent(ScrollView*)
+{
+}
+
+void PluginView::setNPWindowRect(const IntRect&)
+{
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+NPError PluginView::handlePostReadFile(Vector<char>&, uint32_t, const char*)
+{
+ return 0;
+}
+
+bool PluginView::platformGetValue(NPNVariable, void*, NPError*)
+{
+ return false;
+}
+
+bool PluginView::platformGetValueStatic(NPNVariable, void*, NPError*)
+{
+ return false;
+}
+
+void PluginView::invalidateRect(NPRect*)
+{
+}
+#endif
+
+void PluginView::invalidateRect(const IntRect&)
+{
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+void PluginView::invalidateRegion(NPRegion)
+{
+}
+#endif
+
+void PluginView::forceRedraw()
+{
+}
+
+bool PluginView::platformStart()
+{
+ return true;
+}
+
+void PluginView::platformDestroy()
+{
+}
+
+void PluginView::setParentVisible(bool)
+{
+}
+
+void PluginView::updatePluginWidget()
+{
+}
+
+void PluginView::halt()
+{
+}
+
+void PluginView::restart()
+{
+}
+
+#if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
+void PluginView::handleFocusInEvent()
+{
+}
+
+void PluginView::handleFocusOutEvent()
+{
+}
+#endif
+
+// The functions below are for platforms that do not use PluginView for plugins
+// due to architectural differences. The plan is to eventually have all
+// ports using PluginView, but until then, if new functions like this are
+// added, please make sure they have the proper platform #ifs so that changes
+// do not break ports who compile both this file and PluginView.cpp.
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM) || PLATFORM(EFL) || (OS(WINCE) && !PLATFORM(QT)) || (PLATFORM(QT) && !OS(WINCE)) || PLATFORM(BREWMP)
+#if ENABLE(NETSCAPE_PLUGIN_API)
+void PluginView::keepAlive(NPP)
+{
+}
+#endif
+
+#if USE(JSC)
+PassRefPtr<JSC::Bindings::Instance> PluginView::bindingInstance()
+{
+ return 0;
+}
+#endif
+
+void PluginView::privateBrowsingStateChanged(bool)
+{
+}
+
+void PluginView::setJavaScriptPaused(bool)
+{
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/chromium/PluginDataChromium.cpp b/Source/WebCore/plugins/chromium/PluginDataChromium.cpp
new file mode 100644
index 0000000..c924063
--- /dev/null
+++ b/Source/WebCore/plugins/chromium/PluginDataChromium.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2008, 2009, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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 "PluginDataChromium.h"
+
+#include "ChromiumBridge.h"
+
+namespace WebCore {
+
+class PluginCache {
+public:
+ PluginCache() : m_loaded(false), m_refresh(false) {}
+ ~PluginCache() { reset(false); }
+
+ void reset(bool refresh)
+ {
+ m_plugins.clear();
+ m_loaded = false;
+ m_refresh = refresh;
+ }
+
+ const Vector<PluginInfo>& plugins()
+ {
+ if (!m_loaded) {
+ ChromiumBridge::plugins(m_refresh, &m_plugins);
+ m_loaded = true;
+ m_refresh = false;
+ }
+ return m_plugins;
+ }
+
+private:
+ Vector<PluginInfo> m_plugins;
+ bool m_loaded;
+ bool m_refresh;
+};
+
+static PluginCache pluginCache;
+
+void PluginData::initPlugins(const Page*)
+{
+ const Vector<PluginInfo>& plugins = pluginCache.plugins();
+ for (size_t i = 0; i < plugins.size(); ++i)
+ m_plugins.append(plugins[i]);
+}
+
+void PluginData::refresh()
+{
+ pluginCache.reset(true);
+ pluginCache.plugins(); // Force the plugins to be reloaded now.
+}
+
+String getPluginMimeTypeFromExtension(const String& extension)
+{
+ const Vector<PluginInfo>& plugins = pluginCache.plugins();
+ for (size_t i = 0; i < plugins.size(); ++i) {
+ for (size_t j = 0; j < plugins[i].mimes.size(); ++j) {
+ const MimeClassInfo& mime = plugins[i].mimes[j];
+ const Vector<String>& extensions = mime.extensions;
+ for (size_t k = 0; k < extensions.size(); ++k) {
+ if (extension == extensions[k])
+ return mime.type;
+ }
+ }
+ }
+ return String();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/chromium/PluginDataChromium.h b/Source/WebCore/plugins/chromium/PluginDataChromium.h
new file mode 100644
index 0000000..78701b4
--- /dev/null
+++ b/Source/WebCore/plugins/chromium/PluginDataChromium.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 Google, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginDataChromium_h
+#define PluginDataChromium_h
+
+#include "PluginData.h"
+
+namespace WebCore {
+
+// Checks if any of the plugins handle this extension, and if so returns the
+// plugin's mime type for this extension. Otherwise returns an empty string.
+String getPluginMimeTypeFromExtension(const String& extension);
+
+} // namespace WebCore
+
+#endif // PluginDataChromium_h
diff --git a/Source/WebCore/plugins/gtk/PluginDataGtk.cpp b/Source/WebCore/plugins/gtk/PluginDataGtk.cpp
new file mode 100644
index 0000000..705bf9a
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/PluginDataGtk.cpp
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ Copyright (C) 2008 Collabora Ltd. 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"
+#include <stdio.h>
+namespace WebCore {
+
+void PluginData::initPlugins(const Page*)
+{
+ PluginDatabase *db = PluginDatabase::installedPlugins();
+ const Vector<PluginPackage*> &plugins = db->plugins();
+
+ for (unsigned int i = 0; i < plugins.size(); ++i) {
+ PluginInfo info;
+ 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;
+
+ mime.type = it->first;
+ mime.desc = it->second;
+ mime.extensions = package->mimeToExtensions().get(mime.type);
+
+ info.mimes.append(mime);
+ }
+
+ m_plugins.append(info);
+ }
+}
+
+void PluginData::refresh()
+{
+ PluginDatabase *db = PluginDatabase::installedPlugins();
+ db->refresh();
+}
+
+};
diff --git a/Source/WebCore/plugins/gtk/PluginPackageGtk.cpp b/Source/WebCore/plugins/gtk/PluginPackageGtk.cpp
new file mode 100644
index 0000000..a702296
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/PluginPackageGtk.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2008 Novell 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 <gio/gio.h>
+#include <stdio.h>
+
+#include "GOwnPtr.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "npruntime_impl.h"
+#include "PluginDebug.h"
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+bool PluginPackage::fetchInfo()
+{
+#if defined(XP_UNIX)
+ if (!load())
+ return false;
+
+ NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription = 0;
+ NPP_GetValueProcPtr NPP_GetValue = 0;
+
+ g_module_symbol(m_module, "NP_GetMIMEDescription", (void**)&NP_GetMIMEDescription);
+ g_module_symbol(m_module, "NP_GetValue", (void**)&NPP_GetValue);
+
+ if (!NP_GetMIMEDescription || !NPP_GetValue)
+ return false;
+
+ char* buffer = 0;
+ NPError err = NPP_GetValue(0, NPPVpluginNameString, &buffer);
+ if (err == NPERR_NO_ERROR)
+ m_name = buffer;
+
+ buffer = 0;
+ err = NPP_GetValue(0, NPPVpluginDescriptionString, &buffer);
+ if (err == NPERR_NO_ERROR) {
+ m_description = buffer;
+ determineModuleVersionFromDescription();
+ }
+
+ const gchar* types = NP_GetMIMEDescription();
+ if (!types)
+ return true;
+
+ gchar** mimeDescs = g_strsplit(types, ";", -1);
+ for (int i = 0; mimeDescs[i] && mimeDescs[i][0]; i++) {
+ GOwnPtr<char> mime(g_utf8_strdown(mimeDescs[i], -1));
+ gchar** mimeData = g_strsplit(mime.get(), ":", 3);
+ if (g_strv_length(mimeData) < 3) {
+ g_strfreev(mimeData);
+ continue;
+ }
+
+ String description = String::fromUTF8(mimeData[2]);
+ gchar** extensions = g_strsplit(mimeData[1], ",", -1);
+
+ Vector<String> extVector;
+ for (int j = 0; extensions[j]; j++)
+ extVector.append(String::fromUTF8(extensions[j]));
+
+ determineQuirks(mimeData[0]);
+ m_mimeToExtensions.add(mimeData[0], extVector);
+ m_mimeToDescriptions.add(mimeData[0], description);
+
+ g_strfreev(extensions);
+ g_strfreev(mimeData);
+ }
+ g_strfreev(mimeDescs);
+
+ return true;
+#else
+ notImplemented();
+ return false;
+#endif
+}
+
+bool PluginPackage::load()
+{
+ if (m_isLoaded) {
+ m_loadCount++;
+ return true;
+ }
+
+ GOwnPtr<gchar> finalPath(g_strdup(m_path.utf8().data()));
+ while (g_file_test(finalPath.get(), G_FILE_TEST_IS_SYMLINK)) {
+ GOwnPtr<GFile> file(g_file_new_for_path(finalPath.get()));
+ GOwnPtr<GFile> dir(g_file_get_parent(file.get()));
+ GOwnPtr<gchar> linkPath(g_file_read_link(finalPath.get(), 0));
+ GOwnPtr<GFile> resolvedFile(g_file_resolve_relative_path(dir.get(), linkPath.get()));
+ finalPath.set(g_file_get_path(resolvedFile.get()));
+ }
+
+ // No joke. If there is a netscape component in the path, go back
+ // to the symlink, as flash breaks otherwise.
+ // See http://src.chromium.org/viewvc/chrome/trunk/src/webkit/glue/plugins/plugin_list_posix.cc
+ GOwnPtr<gchar> baseName(g_path_get_basename(finalPath.get()));
+ if (!g_strcmp0(baseName.get(), "libflashplayer.so")
+ && g_strstr_len(finalPath.get(), -1, "/netscape/"))
+ finalPath.set(g_strdup(m_path.utf8().data()));
+
+ m_module = g_module_open(finalPath.get(), G_MODULE_BIND_LOCAL);
+
+ if (!m_module) {
+ LOG(Plugins,"Module Load Failed :%s, Error:%s\n", (m_path.utf8()).data(), g_module_error());
+ return false;
+ }
+
+ m_isLoaded = true;
+
+ NP_InitializeFuncPtr NP_Initialize = 0;
+ m_NPP_Shutdown = 0;
+
+ NPError npErr;
+
+ g_module_symbol(m_module, "NP_Initialize", (void**)&NP_Initialize);
+ g_module_symbol(m_module, "NP_Shutdown", (void**)&m_NPP_Shutdown);
+
+ if (!NP_Initialize || !m_NPP_Shutdown)
+ goto abort;
+
+ memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs));
+ m_pluginFuncs.size = sizeof(m_pluginFuncs);
+
+ initializeBrowserFuncs();
+
+#if defined(XP_UNIX)
+ npErr = NP_Initialize(&m_browserFuncs, &m_pluginFuncs);
+#else
+ npErr = NP_Initialize(&m_browserFuncs);
+#endif
+ if (npErr != NPERR_NO_ERROR)
+ goto abort;
+
+ m_loadCount++;
+ return true;
+
+abort:
+ unloadWithoutShutdown();
+ return false;
+}
+
+uint16_t PluginPackage::NPVersion() const
+{
+ return NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL;
+}
+}
diff --git a/Source/WebCore/plugins/gtk/PluginViewGtk.cpp b/Source/WebCore/plugins/gtk/PluginViewGtk.cpp
new file mode 100644
index 0000000..ec855a2
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/PluginViewGtk.cpp
@@ -0,0 +1,901 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2009, 2010 Kakai, Inc. <brian@kakai.com>
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * 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 "Bridge.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "FocusController.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "FrameTree.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
+#include "HostWindow.h"
+#include "Image.h"
+#include "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PluginDebug.h"
+#include "PluginMainThreadScheduler.h"
+#include "PluginPackage.h"
+#include "RenderLayer.h"
+#include "Settings.h"
+#include "JSDOMBinding.h"
+#include "ScriptController.h"
+#include "npruntime_impl.h"
+#include "runtime_root.h"
+#include <runtime/JSLock.h>
+#include <runtime/JSValue.h>
+
+#ifdef GTK_API_VERSION_2
+#include <gdkconfig.h>
+#endif
+#include <gtk/gtk.h>
+
+#if defined(XP_UNIX)
+#include "RefPtrCairo.h"
+#include "gtk2xtbin.h"
+#define Bool int // this got undefined somewhere
+#define Status int // ditto
+#include <X11/extensions/Xrender.h>
+#include <cairo/cairo-xlib.h>
+#include <gdk/gdkx.h>
+#elif defined(GDK_WINDOWING_WIN32)
+#include "PluginMessageThrottlerWin.h"
+#include <gdk/gdkwin32.h>
+#endif
+
+using JSC::ExecState;
+using JSC::Interpreter;
+using JSC::JSLock;
+using JSC::JSObject;
+using JSC::UString;
+
+using std::min;
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+bool PluginView::dispatchNPEvent(NPEvent& event)
+{
+ // sanity check
+ if (!m_plugin->pluginFuncs()->event)
+ return false;
+
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+
+ bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
+
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ return accepted;
+}
+
+#if defined(XP_UNIX)
+static Window getRootWindow(Frame* parentFrame)
+{
+ GtkWidget* parentWidget = parentFrame->view()->hostWindow()->platformPageClient();
+ GdkScreen* gscreen = gtk_widget_get_screen(parentWidget);
+ return GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(gscreen));
+}
+#endif
+
+void PluginView::updatePluginWidget()
+{
+ 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 (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
+ return;
+
+#if defined(XP_UNIX)
+ if (!m_isWindowed) {
+ Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ if (m_drawable)
+ XFreePixmap(display, m_drawable);
+
+ m_drawable = XCreatePixmap(display, getRootWindow(m_parentFrame.get()),
+ m_windowRect.width(), m_windowRect.height(),
+ ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
+ XSync(display, false); // make sure that the server knows about the Drawable
+ }
+#endif
+
+ setNPWindowIfNeeded();
+}
+
+void PluginView::setFocus(bool focused)
+{
+ ASSERT(platformPluginWidget() == platformWidget());
+ Widget::setFocus(focused);
+}
+
+void PluginView::show()
+{
+ ASSERT(platformPluginWidget() == platformWidget());
+ Widget::show();
+}
+
+void PluginView::hide()
+{
+ ASSERT(platformPluginWidget() == platformWidget());
+ Widget::hide();
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_isStarted) {
+ paintMissingPluginIcon(context, rect);
+ return;
+ }
+
+ if (context->paintingDisabled())
+ return;
+
+ setNPWindowIfNeeded();
+
+ if (m_isWindowed)
+ return;
+
+#if defined(XP_UNIX)
+ if (!m_drawable)
+ return;
+
+ Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ const bool syncX = m_pluginDisplay && m_pluginDisplay != display;
+
+ IntRect exposedRect(rect);
+ exposedRect.intersect(frameRect());
+ exposedRect.move(-frameRect().x(), -frameRect().y());
+
+ RefPtr<cairo_surface_t> drawableSurface = adoptRef(cairo_xlib_surface_create(display,
+ m_drawable,
+ m_visual,
+ m_windowRect.width(),
+ m_windowRect.height()));
+
+ if (m_isTransparent) {
+ // If we have a 32 bit drawable and the plugin wants transparency,
+ // we'll clear the exposed area to transparent first. Otherwise,
+ // we'd end up with junk in there from the last paint, or, worse,
+ // uninitialized data.
+ RefPtr<cairo_t> cr = adoptRef(cairo_create(drawableSurface.get()));
+
+ if (!(cairo_surface_get_content(drawableSurface.get()) & CAIRO_CONTENT_ALPHA)) {
+ // Attempt to fake it when we don't have an alpha channel on our
+ // pixmap. If that's not possible, at least clear the window to
+ // avoid drawing artifacts.
+
+ // This Would not work without double buffering, but we always use it.
+ cairo_set_source_surface(cr.get(), cairo_get_group_target(context->platformContext()),
+ -m_windowRect.x(), -m_windowRect.y());
+ cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE);
+ } else
+ cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR);
+
+ cairo_rectangle(cr.get(), exposedRect.x(), exposedRect.y(),
+ exposedRect.width(), exposedRect.height());
+ cairo_fill(cr.get());
+ }
+
+ XEvent xevent;
+ memset(&xevent, 0, sizeof(XEvent));
+ XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
+ exposeEvent.type = GraphicsExpose;
+ exposeEvent.display = display;
+ exposeEvent.drawable = m_drawable;
+ exposeEvent.x = exposedRect.x();
+ exposeEvent.y = exposedRect.y();
+ exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
+ exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
+
+ dispatchNPEvent(xevent);
+
+ if (syncX)
+ XSync(m_pluginDisplay, false); // sync changes by plugin
+
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+
+ cairo_set_source_surface(cr, drawableSurface.get(), frameRect().x(), frameRect().y());
+
+ cairo_rectangle(cr,
+ frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y(),
+ exposedRect.width(), exposedRect.height());
+ cairo_clip(cr);
+
+ if (m_isTransparent)
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ else
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(cr);
+
+ cairo_restore(cr);
+#endif // defined(XP_UNIX)
+}
+
+void PluginView::handleKeyboardEvent(KeyboardEvent* event)
+{
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+
+ if (m_isWindowed)
+ return;
+
+ if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
+ return;
+
+ NPEvent xEvent;
+#if defined(XP_UNIX)
+ initXEvent(&xEvent);
+ GdkEventKey* gdkEvent = event->keyEvent()->gdkEventKey();
+
+ xEvent.type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // KeyPress/Release get unset somewhere
+ xEvent.xkey.root = getRootWindow(m_parentFrame.get());
+ xEvent.xkey.subwindow = 0; // we have no child window
+ xEvent.xkey.time = event->timeStamp();
+ xEvent.xkey.state = gdkEvent->state; // GdkModifierType mirrors xlib state masks
+ xEvent.xkey.keycode = gdkEvent->hardware_keycode;
+ xEvent.xkey.same_screen = true;
+
+ // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
+ // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
+ // set to their normal Xserver values. e.g. Key events don't have a position.
+ // source: https://developer.mozilla.org/en/NPEvent
+ xEvent.xkey.x = 0;
+ xEvent.xkey.y = 0;
+ xEvent.xkey.x_root = 0;
+ xEvent.xkey.y_root = 0;
+#endif
+
+ if (!dispatchNPEvent(xEvent))
+ event->setDefaultHandled();
+}
+
+#if defined(XP_UNIX)
+static unsigned int inputEventState(MouseEvent* event)
+{
+ unsigned int state = 0;
+ if (event->ctrlKey())
+ state |= ControlMask;
+ if (event->shiftKey())
+ state |= ShiftMask;
+ if (event->altKey())
+ state |= Mod1Mask;
+ if (event->metaKey())
+ state |= Mod4Mask;
+ return state;
+}
+
+void PluginView::initXEvent(XEvent* xEvent)
+{
+ memset(xEvent, 0, sizeof(XEvent));
+
+ xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
+ xEvent->xany.send_event = false;
+ xEvent->xany.display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ // NOTE: event->xany.window doesn't always correspond to the .window property of other XEvent's
+ // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify
+ // events; thus, this is right:
+ GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient();
+ xEvent->xany.window = widget ? GDK_WINDOW_XWINDOW(gtk_widget_get_window(widget)) : 0;
+}
+
+static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
+{
+ XButtonEvent& xbutton = xEvent->xbutton;
+ xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
+ xbutton.root = getRootWindow(parentFrame);
+ xbutton.subwindow = 0;
+ xbutton.time = event->timeStamp();
+ xbutton.x = postZoomPos.x();
+ xbutton.y = postZoomPos.y();
+ xbutton.x_root = event->screenX();
+ xbutton.y_root = event->screenY();
+ xbutton.state = inputEventState(event);
+ switch (event->button()) {
+ case MiddleButton:
+ xbutton.button = Button2;
+ break;
+ case RightButton:
+ xbutton.button = Button3;
+ break;
+ case LeftButton:
+ default:
+ xbutton.button = Button1;
+ break;
+ }
+ xbutton.same_screen = true;
+}
+
+static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
+{
+ XMotionEvent& xmotion = xEvent->xmotion;
+ xmotion.type = MotionNotify;
+ xmotion.root = getRootWindow(parentFrame);
+ xmotion.subwindow = 0;
+ xmotion.time = event->timeStamp();
+ xmotion.x = postZoomPos.x();
+ xmotion.y = postZoomPos.y();
+ xmotion.x_root = event->screenX();
+ xmotion.y_root = event->screenY();
+ xmotion.state = inputEventState(event);
+ xmotion.is_hint = NotifyNormal;
+ xmotion.same_screen = true;
+}
+
+static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
+{
+ XCrossingEvent& xcrossing = xEvent->xcrossing;
+ xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
+ xcrossing.root = getRootWindow(parentFrame);
+ xcrossing.subwindow = 0;
+ xcrossing.time = event->timeStamp();
+ xcrossing.x = postZoomPos.y();
+ xcrossing.y = postZoomPos.x();
+ xcrossing.x_root = event->screenX();
+ xcrossing.y_root = event->screenY();
+ xcrossing.state = inputEventState(event);
+ xcrossing.mode = NotifyNormal;
+ xcrossing.detail = NotifyDetailNone;
+ xcrossing.same_screen = true;
+ xcrossing.focus = false;
+}
+#endif
+
+void PluginView::handleMouseEvent(MouseEvent* event)
+{
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+
+ if (m_isWindowed)
+ return;
+
+ if (event->type() == eventNames().mousedownEvent) {
+ if (Page* page = m_parentFrame->page())
+ page->focusController()->setActive(true);
+ focusPluginElement();
+ }
+
+ NPEvent xEvent;
+#if defined(XP_UNIX)
+ initXEvent(&xEvent);
+
+ IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
+
+ if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
+ setXButtonEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
+ else if (event->type() == eventNames().mousemoveEvent)
+ setXMotionEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
+ else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent)
+ setXCrossingEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
+ else
+ return;
+#endif
+
+ if (!dispatchNPEvent(xEvent))
+ event->setDefaultHandled();
+}
+
+#if defined(XP_UNIX)
+void PluginView::handleFocusInEvent()
+{
+ XEvent npEvent;
+ initXEvent(&npEvent);
+
+ XFocusChangeEvent& event = npEvent.xfocus;
+ event.type = 9; // FocusIn gets unset somewhere
+ event.mode = NotifyNormal;
+ event.detail = NotifyDetailNone;
+
+ dispatchNPEvent(npEvent);
+}
+
+void PluginView::handleFocusOutEvent()
+{
+ XEvent npEvent;
+ initXEvent(&npEvent);
+
+ XFocusChangeEvent& event = npEvent.xfocus;
+ event.type = 10; // FocusOut gets unset somewhere
+ event.mode = NotifyNormal;
+ event.detail = NotifyDetailNone;
+
+ dispatchNPEvent(npEvent);
+}
+#endif
+
+void PluginView::setParent(ScrollView* parent)
+{
+ Widget::setParent(parent);
+
+ if (parent)
+ init();
+}
+
+void PluginView::setNPWindowRect(const IntRect&)
+{
+ if (!m_isWindowed)
+ setNPWindowIfNeeded();
+}
+
+void PluginView::setNPWindowIfNeeded()
+{
+ if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
+ return;
+
+ // If the plugin didn't load sucessfully, no point in calling setwindow
+ if (m_status != PluginStatusLoadedSuccessfully)
+ return;
+
+ // On Unix, only call plugin's setwindow if it's full-page or windowed
+ if (m_mode != NP_FULL && m_mode != NP_EMBED)
+ return;
+
+ // Check if the platformPluginWidget still exists
+ if (m_isWindowed && !platformPluginWidget())
+ return;
+
+ if (m_isWindowed) {
+ m_npWindow.x = m_windowRect.x();
+ m_npWindow.y = m_windowRect.y();
+ m_npWindow.width = m_windowRect.width();
+ m_npWindow.height = m_windowRect.height();
+
+ m_npWindow.clipRect.left = max(0, m_clipRect.x());
+ m_npWindow.clipRect.top = max(0, m_clipRect.y());
+ m_npWindow.clipRect.right = m_clipRect.x() + m_clipRect.width();
+ m_npWindow.clipRect.bottom = m_clipRect.y() + m_clipRect.height();
+ } else {
+ m_npWindow.x = 0;
+ m_npWindow.y = 0;
+ m_npWindow.width = m_windowRect.width();
+ m_npWindow.height = m_windowRect.height();
+
+ m_npWindow.clipRect.left = 0;
+ m_npWindow.clipRect.top = 0;
+ m_npWindow.clipRect.right = 0;
+ m_npWindow.clipRect.bottom = 0;
+ }
+
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+
+ if (m_isWindowed) {
+ GtkAllocation allocation = { m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height() };
+ gtk_widget_size_allocate(platformPluginWidget(), &allocation);
+#if defined(XP_UNIX)
+ if (!m_needsXEmbed) {
+ gtk_xtbin_set_position(GTK_XTBIN(platformPluginWidget()), m_windowRect.x(), m_windowRect.y());
+ gtk_xtbin_resize(platformPluginWidget(), m_windowRect.width(), m_windowRect.height());
+ }
+#endif
+ }
+}
+
+void PluginView::setParentVisible(bool visible)
+{
+ if (isParentVisible() == visible)
+ return;
+
+ Widget::setParentVisible(visible);
+
+ if (isSelfVisible() && platformPluginWidget()) {
+ if (visible)
+ gtk_widget_show(platformPluginWidget());
+ else
+ gtk_widget_hide(platformPluginWidget());
+ }
+}
+
+NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
+{
+ WTF::String filename(buf, len);
+
+ if (filename.startsWith("file:///"))
+ filename = filename.substring(8);
+
+ // Get file info
+ if (!g_file_test ((filename.utf8()).data(), (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)))
+ return NPERR_FILE_NOT_FOUND;
+
+ //FIXME - read the file data into buffer
+ FILE* fileHandle = fopen((filename.utf8()).data(), "r");
+
+ if (fileHandle == 0)
+ return NPERR_FILE_NOT_FOUND;
+
+ //buffer.resize();
+
+ int bytesRead = fread(buffer.data(), 1, 0, fileHandle);
+
+ fclose(fileHandle);
+
+ if (bytesRead <= 0)
+ return NPERR_FILE_NOT_FOUND;
+
+ return NPERR_NO_ERROR;
+}
+
+bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
+{
+ switch (variable) {
+ case NPNVToolkit:
+#if defined(XP_UNIX)
+ *static_cast<uint32_t*>(value) = 2;
+#else
+ *static_cast<uint32_t*>(value) = 0;
+#endif
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVSupportsXEmbedBool:
+#if defined(XP_UNIX)
+ *static_cast<NPBool*>(value) = true;
+#else
+ *static_cast<NPBool*>(value) = false;
+#endif
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVjavascriptEnabledBool:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVSupportsWindowless:
+#if defined(XP_UNIX)
+ *static_cast<NPBool*>(value) = true;
+#else
+ *static_cast<NPBool*>(value) = false;
+#endif
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
+{
+ switch (variable) {
+ case NPNVxDisplay:
+#if defined(XP_UNIX)
+ if (m_needsXEmbed)
+ *(void **)value = (void *)GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ else
+ *(void **)value = (void *)GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay;
+ *result = NPERR_NO_ERROR;
+#else
+ *result = NPERR_GENERIC_ERROR;
+#endif
+ return true;
+
+#if defined(XP_UNIX)
+ case NPNVxtAppContext:
+ if (!m_needsXEmbed) {
+ *(void **)value = XtDisplayToApplicationContext (GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay);
+
+ *result = NPERR_NO_ERROR;
+ } else
+ *result = NPERR_GENERIC_ERROR;
+ return true;
+#endif
+
+ case NPNVnetscapeWindow: {
+#if defined(XP_UNIX)
+ void* w = reinterpret_cast<void*>(value);
+ GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient();
+ *((XID *)w) = GDK_WINDOW_XWINDOW(gtk_widget_get_window(widget));
+#endif
+#ifdef GDK_WINDOWING_WIN32
+ HGDIOBJ* w = reinterpret_cast<HGDIOBJ*>(value);
+ GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient();
+ *w = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
+#endif
+ *result = NPERR_NO_ERROR;
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+void PluginView::invalidateRect(const IntRect& rect)
+{
+ if (m_isWindowed) {
+ gtk_widget_queue_draw_area(GTK_WIDGET(platformPluginWidget()), rect.x(), rect.y(), rect.width(), rect.height());
+ 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);
+ invalidateWindowlessPluginRect(r);
+}
+
+void PluginView::invalidateRegion(NPRegion)
+{
+ // TODO: optimize
+ invalidate();
+}
+
+void PluginView::forceRedraw()
+{
+ if (m_isWindowed)
+ gtk_widget_queue_draw(platformPluginWidget());
+ else
+ gtk_widget_queue_draw(m_parentFrame->view()->hostWindow()->platformPageClient());
+}
+
+static Display* getPluginDisplay()
+{
+ // The plugin toolkit might have a different X connection open. Since we're
+ // a gdk/gtk app, we'll (probably?) have the same X connection as any gdk-based
+ // plugins, so we can return that. We might want to add other implementations here
+ // later.
+
+#if defined(XP_UNIX)
+ return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+#else
+ return 0;
+#endif
+}
+
+#if defined(XP_UNIX)
+static void getVisualAndColormap(int depth, Visual** visual, Colormap* colormap)
+{
+ *visual = 0;
+ *colormap = 0;
+
+ Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ int rmaj, rmin;
+ if (depth == 32 && (!XRenderQueryVersion(display, &rmaj, &rmin) || (rmaj == 0 && rmin < 5)))
+ return;
+
+ XVisualInfo templ;
+ templ.screen = gdk_screen_get_number(gdk_screen_get_default());
+ templ.depth = depth;
+ templ.c_class = TrueColor;
+ int nVisuals;
+ XVisualInfo* visualInfo = XGetVisualInfo(display, VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nVisuals);
+
+ if (!nVisuals)
+ return;
+
+ if (depth == 32) {
+ for (int idx = 0; idx < nVisuals; ++idx) {
+ XRenderPictFormat* format = XRenderFindVisualFormat(display, visualInfo[idx].visual);
+ if (format->type == PictTypeDirect && format->direct.alphaMask) {
+ *visual = visualInfo[idx].visual;
+ break;
+ }
+ }
+ } else
+ *visual = visualInfo[0].visual;
+
+ XFree(visualInfo);
+
+ if (*visual)
+ *colormap = XCreateColormap(display, GDK_ROOT_WINDOW(), *visual, AllocNone);
+}
+#endif
+
+static gboolean plugRemovedCallback(GtkSocket* socket, gpointer)
+{
+ return TRUE;
+}
+
+static void plugAddedCallback(GtkSocket* socket, PluginView* view)
+{
+ if (!socket || !view)
+ return;
+
+ // FIXME: Java Plugins do not seem to draw themselves properly the
+ // first time unless we do a size-allocate after they have done
+ // the plug operation on their side, which in general does not
+ // happen since we do size-allocates before setting the
+ // NPWindow. Apply this workaround until we figure out a better
+ // solution, if any.
+ IntRect rect = view->frameRect();
+ GtkAllocation allocation = { rect.x(), rect.y(), rect.width(), rect.height() };
+ gtk_widget_size_allocate(GTK_WIDGET(socket), &allocation);
+}
+
+bool PluginView::platformStart()
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_status == PluginStatusLoadedSuccessfully);
+
+ if (m_plugin->pluginFuncs()->getvalue) {
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ }
+
+ if (m_isWindowed) {
+#if defined(XP_UNIX)
+ GtkWidget* pageClient = m_parentFrame->view()->hostWindow()->platformPageClient();
+
+ if (m_needsXEmbed) {
+ // If our parent is not anchored the startup process will
+ // fail miserably for XEmbed plugins a bit later on when
+ // we try to get the ID of our window (since realize will
+ // fail), so let's just abort here.
+ if (!gtk_widget_get_parent(pageClient))
+ return false;
+
+ setPlatformWidget(gtk_socket_new());
+ gtk_container_add(GTK_CONTAINER(pageClient), platformPluginWidget());
+ g_signal_connect(platformPluginWidget(), "plug-added", G_CALLBACK(plugAddedCallback), this);
+ g_signal_connect(platformPluginWidget(), "plug-removed", G_CALLBACK(plugRemovedCallback), NULL);
+ } else
+ setPlatformWidget(gtk_xtbin_new(pageClient, 0));
+#else
+ setPlatformWidget(gtk_socket_new());
+ gtk_container_add(GTK_CONTAINER(pageClient), platformPluginWidget());
+#endif
+ } else {
+ setPlatformWidget(0);
+ m_pluginDisplay = getPluginDisplay();
+ }
+
+ show();
+
+#if defined(XP_UNIX)
+ NPSetWindowCallbackStruct* ws = new NPSetWindowCallbackStruct();
+ ws->type = 0;
+#endif
+
+ if (m_isWindowed) {
+ m_npWindow.type = NPWindowTypeWindow;
+#if defined(XP_UNIX)
+ if (m_needsXEmbed) {
+ GtkWidget* widget = platformPluginWidget();
+ gtk_widget_realize(widget);
+ m_npWindow.window = (void*)gtk_socket_get_id(GTK_SOCKET(platformPluginWidget()));
+ GdkWindow* window = gtk_widget_get_window(widget);
+ ws->display = GDK_WINDOW_XDISPLAY(window);
+ ws->visual = GDK_VISUAL_XVISUAL(gdk_window_get_visual(window));
+ ws->depth = gdk_visual_get_depth(gdk_window_get_visual(window));
+ ws->colormap = XCreateColormap(ws->display, GDK_ROOT_WINDOW(), ws->visual, AllocNone);
+ } else {
+ m_npWindow.window = (void*)GTK_XTBIN(platformPluginWidget())->xtwindow;
+ ws->display = GTK_XTBIN(platformPluginWidget())->xtdisplay;
+ ws->visual = GTK_XTBIN(platformPluginWidget())->xtclient.xtvisual;
+ ws->depth = GTK_XTBIN(platformPluginWidget())->xtclient.xtdepth;
+ ws->colormap = GTK_XTBIN(platformPluginWidget())->xtclient.xtcolormap;
+ }
+ XFlush (ws->display);
+#elif defined(GDK_WINDOWING_WIN32)
+ m_npWindow.window = (void*)GDK_WINDOW_HWND(gtk_widget_get_window(platformPluginWidget()));
+#endif
+ } else {
+ m_npWindow.type = NPWindowTypeDrawable;
+ m_npWindow.window = 0; // Not used?
+
+#if defined(XP_UNIX)
+ GdkScreen* gscreen = gdk_screen_get_default();
+ GdkVisual* gvisual = gdk_screen_get_system_visual(gscreen);
+
+ if (gdk_visual_get_depth(gvisual) == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) {
+ getVisualAndColormap(32, &m_visual, &m_colormap);
+ ws->depth = 32;
+ }
+
+ if (!m_visual) {
+ getVisualAndColormap(gdk_visual_get_depth(gvisual), &m_visual, &m_colormap);
+ ws->depth = gdk_visual_get_depth(gvisual);
+ }
+
+ ws->display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ ws->visual = m_visual;
+ ws->colormap = m_colormap;
+
+ m_npWindow.x = 0;
+ m_npWindow.y = 0;
+ m_npWindow.width = -1;
+ m_npWindow.height = -1;
+#else
+ notImplemented();
+ m_status = PluginStatusCanNotLoadPlugin;
+ return false;
+#endif
+ }
+
+#if defined(XP_UNIX)
+ m_npWindow.ws_info = ws;
+#endif
+
+ // TODO remove in favor of null events, like mac port?
+ if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall)))
+ updatePluginWidget(); // was: setNPWindowIfNeeded(), but this doesn't produce 0x0 rects at first go
+
+ return true;
+}
+
+void PluginView::platformDestroy()
+{
+#if defined(XP_UNIX)
+ if (m_drawable) {
+ XFreePixmap(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), m_drawable);
+ m_drawable = 0;
+ }
+#endif
+}
+
+void PluginView::halt()
+{
+}
+
+void PluginView::restart()
+{
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/plugins/gtk/gtk2xtbin.c b/Source/WebCore/plugins/gtk/gtk2xtbin.c
new file mode 100644
index 0000000..e03fad3
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/gtk2xtbin.c
@@ -0,0 +1,966 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim:expandtab:shiftwidth=2:tabstop=2: */
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Gtk2XtBin Widget Implementation.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * The GtkXtBin widget allows for Xt toolkit code to be used
+ * inside a GTK application.
+ */
+
+#include "GtkVersioning.h"
+#include "xembed.h"
+#include "gtk2xtbin.h"
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <glib.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Xlib/Xt stuff */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Shell.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+
+/* uncomment this if you want debugging information about widget
+ creation and destruction */
+#undef DEBUG_XTBIN
+
+#define XTBIN_MAX_EVENTS 30
+
+static void gtk_xtbin_class_init (GtkXtBinClass *klass);
+static void gtk_xtbin_init (GtkXtBin *xtbin);
+static void gtk_xtbin_realize (GtkWidget *widget);
+static void gtk_xtbin_unrealize (GtkWidget *widget);
+static void gtk_xtbin_dispose (GObject *object);
+
+/* Xt aware XEmbed */
+static void xt_client_init (XtClient * xtclient,
+ Visual *xtvisual,
+ Colormap xtcolormap,
+ int xtdepth);
+static void xt_client_create (XtClient * xtclient,
+ Window embeder,
+ int height,
+ int width );
+static void xt_client_unrealize (XtClient* xtclient);
+static void xt_client_destroy (XtClient* xtclient);
+static void xt_client_set_info (Widget xtplug,
+ unsigned long flags);
+static void xt_client_event_handler (Widget w,
+ XtPointer client_data,
+ XEvent *event);
+static void xt_client_handle_xembed_message (Widget w,
+ XtPointer client_data,
+ XEvent *event);
+static void xt_client_focus_listener (Widget w,
+ XtPointer user_data,
+ XEvent *event);
+static void xt_add_focus_listener( Widget w, XtPointer user_data );
+static void xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data);
+static void xt_remove_focus_listener(Widget w, XtPointer user_data);
+static void send_xembed_message (XtClient *xtclient,
+ long message,
+ long detail,
+ long data1,
+ long data2,
+ long time);
+static int error_handler (Display *display,
+ XErrorEvent *error);
+/* For error trap of XEmbed */
+static void trap_errors(void);
+static int untrap_error(void);
+static int (*old_error_handler) (Display *, XErrorEvent *);
+static int trapped_error_code = 0;
+
+static GtkWidgetClass *parent_class = NULL;
+
+static Display *xtdisplay = NULL;
+static String *fallback = NULL;
+static gboolean xt_is_initialized = FALSE;
+static gint num_widgets = 0;
+
+static GPollFD xt_event_poll_fd;
+static gint xt_polling_timer_id = 0;
+static guint tag = 0;
+
+static gboolean
+xt_event_prepare (GSource* source_data,
+ gint *timeout)
+{
+ int mask;
+
+ GDK_THREADS_ENTER();
+ mask = XPending(xtdisplay);
+ GDK_THREADS_LEAVE();
+
+ return (gboolean)mask;
+}
+
+static gboolean
+xt_event_check (GSource* source_data)
+{
+ GDK_THREADS_ENTER ();
+
+ if (xt_event_poll_fd.revents & G_IO_IN) {
+ int mask;
+ mask = XPending(xtdisplay);
+ GDK_THREADS_LEAVE ();
+ return (gboolean)mask;
+ }
+
+ GDK_THREADS_LEAVE ();
+ return FALSE;
+}
+
+static gboolean
+xt_event_dispatch (GSource* source_data,
+ GSourceFunc call_back,
+ gpointer user_data)
+{
+ XtAppContext ac;
+ int i = 0;
+
+ ac = XtDisplayToApplicationContext(xtdisplay);
+
+ GDK_THREADS_ENTER ();
+
+ /* Process only real X traffic here. We only look for data on the
+ * pipe, limit it to XTBIN_MAX_EVENTS and only call
+ * XtAppProcessEvent so that it will look for X events. There's no
+ * timer processing here since we already have a timer callback that
+ * does it. */
+ for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) {
+ XtAppProcessEvent(ac, XtIMXEvent);
+ }
+
+ GDK_THREADS_LEAVE ();
+
+ return TRUE;
+}
+
+typedef void (*GSourceFuncsFinalize) (GSource* source);
+
+static GSourceFuncs xt_event_funcs = {
+ xt_event_prepare,
+ xt_event_check,
+ xt_event_dispatch,
+ (GSourceFuncsFinalize)g_free,
+ (GSourceFunc)NULL,
+ (GSourceDummyMarshal)NULL
+};
+
+static gboolean
+xt_event_polling_timer_callback(gpointer user_data)
+{
+ Display * display;
+ XtAppContext ac;
+ int eventsToProcess = 20;
+
+ display = (Display *)user_data;
+ ac = XtDisplayToApplicationContext(display);
+
+ /* We need to process many Xt events here. If we just process
+ one event we might starve one or more Xt consumers. On the other hand
+ this could hang the whole app if Xt events come pouring in. So process
+ up to 20 Xt events right now and save the rest for later. This is a hack,
+ but it oughta work. We *really* should have out of process plugins.
+ */
+ while (eventsToProcess-- && XtAppPending(ac))
+ XtAppProcessEvent(ac, XtIMAll);
+ return TRUE;
+}
+
+GType
+gtk_xtbin_get_type (void)
+{
+ static GType xtbin_type = 0;
+
+ if (!xtbin_type) {
+ static const GTypeInfo xtbin_info =
+ {
+ sizeof (GtkXtBinClass),
+ NULL,
+ NULL,
+
+ (GClassInitFunc)gtk_xtbin_class_init,
+ NULL,
+ NULL,
+
+ sizeof (GtkXtBin),
+ 0,
+ (GInstanceInitFunc)gtk_xtbin_init,
+ NULL
+ };
+ xtbin_type = g_type_register_static (GTK_TYPE_SOCKET,
+ "GtkXtBin",
+ &xtbin_info,
+ 0);
+ }
+ return xtbin_type;
+}
+
+static void
+gtk_xtbin_class_init (GtkXtBinClass *klass)
+{
+ GtkWidgetClass *widget_class;
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ widget_class = GTK_WIDGET_CLASS (klass);
+ widget_class->realize = gtk_xtbin_realize;
+ widget_class->unrealize = gtk_xtbin_unrealize;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = gtk_xtbin_dispose;
+}
+
+static void
+gtk_xtbin_init (GtkXtBin *xtbin)
+{
+ xtbin->xtdisplay = NULL;
+ xtbin->parent_window = NULL;
+ xtbin->xtwindow = 0;
+ xtbin->x = 0;
+ xtbin->y = 0;
+}
+
+static void
+gtk_xtbin_realize (GtkWidget *widget)
+{
+ GtkXtBin *xtbin;
+ GtkAllocation allocation = { 0, 0, 200, 200 };
+#if GTK_CHECK_VERSION(2, 18, 0)
+ GtkAllocation widget_allocation;
+#endif
+
+#ifdef DEBUG_XTBIN
+ printf("gtk_xtbin_realize()\n");
+#endif
+
+ g_return_if_fail (GTK_IS_XTBIN (widget));
+
+ xtbin = GTK_XTBIN (widget);
+
+ /* caculate the allocation before realize */
+#if GTK_CHECK_VERSION(2, 24, 0)
+ allocation.width = gdk_window_get_width(xtbin->parent_window);
+ allocation.height = gdk_window_get_height(xtbin->parent_window);
+#else
+ gint x, y, w, h, d; /* geometry of window */
+ gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d);
+ allocation.width = w;
+ allocation.height = h;
+#endif
+ gtk_widget_size_allocate (widget, &allocation);
+
+#ifdef DEBUG_XTBIN
+ printf("initial allocation %d %d %d %d\n", x, y, w, h);
+#endif
+
+#if GTK_CHECK_VERSION(2, 18, 0)
+ gtk_widget_get_allocation(widget, &widget_allocation);
+ xtbin->width = widget_allocation.width;
+ xtbin->height = widget_allocation.height;
+#else
+ xtbin->width = widget->allocation.width;
+ xtbin->height = widget->allocation.height;
+#endif
+
+ /* use GtkSocket's realize */
+ (*GTK_WIDGET_CLASS(parent_class)->realize)(widget);
+
+ /* create the Xt client widget */
+ xt_client_create(&(xtbin->xtclient),
+ gtk_socket_get_id(GTK_SOCKET(xtbin)),
+ xtbin->height,
+ xtbin->width);
+ xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget);
+
+ gdk_flush();
+
+ /* now that we have created the xt client, add it to the socket. */
+ gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow);
+}
+
+
+
+GtkWidget*
+gtk_xtbin_new (GtkWidget *parent_widget, String *f)
+{
+ GtkXtBin *xtbin;
+ gpointer user_data;
+ GdkScreen *screen;
+ GdkVisual* visual;
+ Colormap colormap;
+ GdkWindow* parent_window = gtk_widget_get_window(parent_widget);
+
+ assert(parent_window != NULL);
+ xtbin = g_object_new (GTK_TYPE_XTBIN, NULL);
+
+ if (!xtbin)
+ return (GtkWidget*)NULL;
+
+ if (f)
+ fallback = f;
+
+ /* Initialize the Xt toolkit */
+ xtbin->parent_window = parent_window;
+
+ screen = gtk_widget_get_screen(parent_widget);
+ visual = gdk_screen_get_system_visual(screen);
+ colormap = XCreateColormap(GDK_DISPLAY_XDISPLAY(gdk_screen_get_display(screen)),
+ GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(screen)),
+ GDK_VISUAL_XVISUAL(visual), AllocNone);
+
+ xt_client_init(&(xtbin->xtclient),
+ GDK_VISUAL_XVISUAL(visual),
+ colormap,
+ gdk_visual_get_depth(visual));
+
+ if (!xtbin->xtclient.xtdisplay) {
+ /* If XtOpenDisplay failed, we can't go any further.
+ * Bail out.
+ */
+#ifdef DEBUG_XTBIN
+ printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
+#endif
+ g_free (xtbin);
+ return (GtkWidget *)NULL;
+ }
+
+ /* If this is the first running widget, hook this display into the
+ mainloop */
+ if (0 == num_widgets) {
+ int cnumber;
+ /*
+ * hook Xt event loop into the glib event loop.
+ */
+
+ /* the assumption is that gtk_init has already been called */
+ GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource));
+ if (!gs) {
+ return NULL;
+ }
+
+ g_source_set_priority(gs, GDK_PRIORITY_EVENTS);
+ g_source_set_can_recurse(gs, TRUE);
+ tag = g_source_attach(gs, (GMainContext*)NULL);
+#ifdef VMS
+ cnumber = XConnectionNumber(xtdisplay);
+#else
+ cnumber = ConnectionNumber(xtdisplay);
+#endif
+ xt_event_poll_fd.fd = cnumber;
+ xt_event_poll_fd.events = G_IO_IN;
+ xt_event_poll_fd.revents = 0; /* hmm... is this correct? */
+
+ g_main_context_add_poll ((GMainContext*)NULL,
+ &xt_event_poll_fd,
+ G_PRIORITY_LOW);
+ /* add a timer so that we can poll and process Xt timers */
+ xt_polling_timer_id =
+ g_timeout_add(25,
+ (GSourceFunc)xt_event_polling_timer_callback,
+ xtdisplay);
+ }
+
+ /* Bump up our usage count */
+ num_widgets++;
+
+ /* Build the hierachy */
+ xtbin->xtdisplay = xtbin->xtclient.xtdisplay;
+ gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window);
+ gdk_window_get_user_data(xtbin->parent_window, &user_data);
+ if (user_data)
+ gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin));
+
+ return GTK_WIDGET (xtbin);
+}
+
+void
+gtk_xtbin_set_position (GtkXtBin *xtbin,
+ gint x,
+ gint y)
+{
+ xtbin->x = x;
+ xtbin->y = y;
+
+ if (gtk_widget_get_realized (GTK_WIDGET(xtbin)))
+ gdk_window_move (gtk_widget_get_window(GTK_WIDGET (xtbin)), x, y);
+}
+
+void
+gtk_xtbin_resize (GtkWidget *widget,
+ gint width,
+ gint height)
+{
+ Arg args[2];
+ GtkXtBin *xtbin = GTK_XTBIN (widget);
+ GtkAllocation allocation;
+
+#ifdef DEBUG_XTBIN
+ printf("gtk_xtbin_resize %p %d %d\n", (void *)widget, width, height);
+#endif
+
+ xtbin->height = height;
+ xtbin->width = width;
+
+ // Avoid BadValue errors in XtSetValues
+ if (height <= 0 || width <=0) {
+ height = 1;
+ width = 1;
+ }
+ XtSetArg(args[0], XtNheight, height);
+ XtSetArg(args[1], XtNwidth, width);
+ XtSetValues(xtbin->xtclient.top_widget, args, 2);
+
+ /* we need to send a size allocate so the socket knows about the
+ size changes */
+ allocation.x = xtbin->x;
+ allocation.y = xtbin->y;
+ allocation.width = xtbin->width;
+ allocation.height = xtbin->height;
+
+ gtk_widget_size_allocate(widget, &allocation);
+}
+
+static void
+gtk_xtbin_unrealize (GtkWidget *object)
+{
+ GtkXtBin *xtbin;
+ GtkWidget *widget;
+
+#ifdef DEBUG_XTBIN
+ printf("gtk_xtbin_unrealize()\n");
+#endif
+
+ /* gtk_object_destroy() will already hold a refcount on object
+ */
+ xtbin = GTK_XTBIN(object);
+ widget = GTK_WIDGET(object);
+
+ gtk_widget_set_visible(widget, FALSE);
+ if (gtk_widget_get_realized (widget)) {
+ xt_client_unrealize(&(xtbin->xtclient));
+ }
+
+ (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
+}
+
+static void
+gtk_xtbin_dispose (GObject *object)
+{
+ GtkXtBin *xtbin;
+
+#ifdef DEBUG_XTBIN
+ printf("gtk_xtbin_destroy()\n");
+#endif
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GTK_IS_XTBIN (object));
+
+ xtbin = GTK_XTBIN (object);
+
+ if(xtbin->xtwindow) {
+ /* remove the event handler */
+ xt_client_destroy(&(xtbin->xtclient));
+ xtbin->xtwindow = 0;
+
+ num_widgets--; /* reduce our usage count */
+
+ /* If this is the last running widget, remove the Xt display
+ connection from the mainloop */
+ if (0 == num_widgets) {
+#ifdef DEBUG_XTBIN
+ printf("removing the Xt connection from the main loop\n");
+#endif
+ g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd);
+ g_source_remove(tag);
+
+ g_source_remove(xt_polling_timer_id);
+ xt_polling_timer_id = 0;
+ }
+ }
+
+ G_OBJECT_CLASS(parent_class)->dispose(object);
+}
+
+/*
+* Following is the implementation of Xt XEmbedded for client side
+*/
+
+/* Initial Xt plugin */
+static void
+xt_client_init( XtClient * xtclient,
+ Visual *xtvisual,
+ Colormap xtcolormap,
+ int xtdepth)
+{
+ XtAppContext app_context;
+ char *mArgv[1];
+ int mArgc = 0;
+
+ /*
+ * Initialize Xt stuff
+ */
+ xtclient->top_widget = NULL;
+ xtclient->child_widget = NULL;
+ xtclient->xtdisplay = NULL;
+ xtclient->xtvisual = NULL;
+ xtclient->xtcolormap = 0;
+ xtclient->xtdepth = 0;
+
+ if (!xt_is_initialized) {
+#ifdef DEBUG_XTBIN
+ printf("starting up Xt stuff\n");
+#endif
+ XtToolkitInitialize();
+ app_context = XtCreateApplicationContext();
+ if (fallback)
+ XtAppSetFallbackResources(app_context, fallback);
+
+ xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL,
+ "Wrapper", NULL, 0, &mArgc, mArgv);
+ if (xtdisplay)
+ xt_is_initialized = TRUE;
+ }
+ xtclient->xtdisplay = xtdisplay;
+ xtclient->xtvisual = xtvisual;
+ xtclient->xtcolormap = xtcolormap;
+ xtclient->xtdepth = xtdepth;
+}
+
+/* Create the Xt client widgets
+* */
+static void
+xt_client_create ( XtClient* xtclient ,
+ Window embedderid,
+ int height,
+ int width )
+{
+ int n;
+ Arg args[6];
+ Widget child_widget;
+ Widget top_widget;
+
+#ifdef DEBUG_XTBIN
+ printf("xt_client_create() \n");
+#endif
+ top_widget = XtAppCreateShell("drawingArea", "Wrapper",
+ applicationShellWidgetClass,
+ xtclient->xtdisplay,
+ NULL, 0);
+ xtclient->top_widget = top_widget;
+
+ /* set size of Xt window */
+ n = 0;
+ XtSetArg(args[n], XtNheight, height);n++;
+ XtSetArg(args[n], XtNwidth, width);n++;
+ XtSetValues(top_widget, args, n);
+
+ child_widget = XtVaCreateWidget("form",
+ compositeWidgetClass,
+ top_widget, NULL);
+
+ n = 0;
+ XtSetArg(args[n], XtNheight, height);n++;
+ XtSetArg(args[n], XtNwidth, width);n++;
+ XtSetArg(args[n], XtNvisual, xtclient->xtvisual ); n++;
+ XtSetArg(args[n], XtNdepth, xtclient->xtdepth ); n++;
+ XtSetArg(args[n], XtNcolormap, xtclient->xtcolormap ); n++;
+ XtSetArg(args[n], XtNborderWidth, 0); n++;
+ XtSetValues(child_widget, args, n);
+
+ XSync(xtclient->xtdisplay, FALSE);
+ xtclient->oldwindow = top_widget->core.window;
+ top_widget->core.window = embedderid;
+
+ /* this little trick seems to finish initializing the widget */
+#if XlibSpecificationRelease >= 6
+ XtRegisterDrawable(xtclient->xtdisplay,
+ embedderid,
+ top_widget);
+#else
+ _XtRegisterWindow( embedderid,
+ top_widget);
+#endif
+ XtRealizeWidget(child_widget);
+
+ /* listen to all Xt events */
+ XSelectInput(xtclient->xtdisplay,
+ XtWindow(top_widget),
+ 0x0FFFFF);
+ xt_client_set_info (child_widget, 0);
+
+ XtManageChild(child_widget);
+ xtclient->child_widget = child_widget;
+
+ /* set the event handler */
+ XtAddEventHandler(child_widget,
+ 0x0FFFFF & ~ResizeRedirectMask,
+ TRUE,
+ (XtEventHandler)xt_client_event_handler, xtclient);
+ XtAddEventHandler(child_widget,
+ SubstructureNotifyMask | ButtonReleaseMask,
+ TRUE,
+ (XtEventHandler)xt_client_focus_listener,
+ xtclient);
+ XSync(xtclient->xtdisplay, FALSE);
+}
+
+static void
+xt_client_unrealize ( XtClient* xtclient )
+{
+#if XlibSpecificationRelease >= 6
+ XtUnregisterDrawable(xtclient->xtdisplay,
+ xtclient->top_widget->core.window);
+#else
+ _XtUnregisterWindow(xtclient->top_widget->core.window,
+ xtclient->top_widget);
+#endif
+
+ /* flush the queue before we returning origin top_widget->core.window
+ or we can get X error since the window is gone */
+ XSync(xtclient->xtdisplay, False);
+
+ xtclient->top_widget->core.window = xtclient->oldwindow;
+ XtUnrealizeWidget(xtclient->top_widget);
+}
+
+static void
+xt_client_destroy (XtClient* xtclient)
+{
+ if(xtclient->top_widget) {
+ XtRemoveEventHandler(xtclient->child_widget, 0x0FFFFF, TRUE,
+ (XtEventHandler)xt_client_event_handler, xtclient);
+ XtDestroyWidget(xtclient->top_widget);
+ xtclient->top_widget = NULL;
+ }
+}
+
+static void
+xt_client_set_info (Widget xtplug, unsigned long flags)
+{
+ unsigned long buffer[2];
+
+ Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False);
+
+ buffer[1] = 0; /* Protocol version */
+ buffer[1] = flags;
+
+ XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug),
+ infoAtom, infoAtom, 32,
+ PropModeReplace,
+ (unsigned char *)buffer, 2);
+}
+
+static void
+xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event)
+{
+ XtClient *xtplug = (XtClient*)client_data;
+ switch (event->xclient.data.l[1])
+ {
+ case XEMBED_EMBEDDED_NOTIFY:
+ break;
+ case XEMBED_WINDOW_ACTIVATE:
+#ifdef DEBUG_XTBIN
+ printf("Xt client get XEMBED_WINDOW_ACTIVATE\n");
+#endif
+ break;
+ case XEMBED_WINDOW_DEACTIVATE:
+#ifdef DEBUG_XTBIN
+ printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n");
+#endif
+ break;
+ case XEMBED_MODALITY_ON:
+#ifdef DEBUG_XTBIN
+ printf("Xt client get XEMBED_MODALITY_ON\n");
+#endif
+ break;
+ case XEMBED_MODALITY_OFF:
+#ifdef DEBUG_XTBIN
+ printf("Xt client get XEMBED_MODALITY_OFF\n");
+#endif
+ break;
+ case XEMBED_FOCUS_IN:
+ case XEMBED_FOCUS_OUT:
+ {
+ XEvent xevent;
+ memset(&xevent, 0, sizeof(xevent));
+
+ if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) {
+#ifdef DEBUG_XTBIN
+ printf("XTEMBED got focus in\n");
+#endif
+ xevent.xfocus.type = FocusIn;
+ }
+ else {
+#ifdef DEBUG_XTBIN
+ printf("XTEMBED got focus out\n");
+#endif
+ xevent.xfocus.type = FocusOut;
+ }
+
+ xevent.xfocus.window = XtWindow(xtplug->child_widget);
+ xevent.xfocus.display = XtDisplay(xtplug->child_widget);
+ XSendEvent(XtDisplay(xtplug->child_widget),
+ xevent.xfocus.window,
+ False, NoEventMask,
+ &xevent );
+ XSync( XtDisplay(xtplug->child_widget), False);
+ }
+ break;
+ default:
+ break;
+ } /* End of XEmbed Message */
+}
+
+static void
+xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event)
+{
+ XtClient *xtplug = (XtClient*)client_data;
+
+ switch(event->type)
+ {
+ case ClientMessage:
+ /* Handle xembed message */
+ if (event->xclient.message_type==
+ XInternAtom (XtDisplay(xtplug->child_widget),
+ "_XEMBED", False)) {
+ xt_client_handle_xembed_message(w, client_data, event);
+ }
+ break;
+ case ReparentNotify:
+ break;
+ case MappingNotify:
+ xt_client_set_info (w, XEMBED_MAPPED);
+ break;
+ case UnmapNotify:
+ xt_client_set_info (w, 0);
+ break;
+ case FocusIn:
+ send_xembed_message ( xtplug,
+ XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
+ break;
+ case FocusOut:
+ break;
+ case KeyPress:
+#ifdef DEBUG_XTBIN
+ printf("Key Press Got!\n");
+#endif
+ break;
+ default:
+ break;
+ } /* End of switch(event->type) */
+}
+
+static void
+send_xembed_message (XtClient *xtclient,
+ long message,
+ long detail,
+ long data1,
+ long data2,
+ long time)
+{
+ XEvent xevent;
+ Window w=XtWindow(xtclient->top_widget);
+ Display* dpy=xtclient->xtdisplay;
+ int errorcode;
+
+ memset(&xevent,0,sizeof(xevent));
+ xevent.xclient.window = w;
+ xevent.xclient.type = ClientMessage;
+ xevent.xclient.message_type = XInternAtom(dpy,"_XEMBED",False);
+ xevent.xclient.format = 32;
+ xevent.xclient.data.l[0] = time;
+ xevent.xclient.data.l[1] = message;
+ xevent.xclient.data.l[2] = detail;
+ xevent.xclient.data.l[3] = data1;
+ xevent.xclient.data.l[4] = data2;
+
+ trap_errors ();
+ XSendEvent (dpy, w, False, NoEventMask, &xevent);
+ XSync (dpy,False);
+
+ if((errorcode = untrap_error())) {
+#ifdef DEBUG_XTBIN
+ printf("send_xembed_message error(%d)!!!\n",errorcode);
+#endif
+ }
+}
+
+static int
+error_handler(Display *display, XErrorEvent *error)
+{
+ trapped_error_code = error->error_code;
+ return 0;
+}
+
+static void
+trap_errors(void)
+{
+ trapped_error_code =0;
+ old_error_handler = XSetErrorHandler(error_handler);
+}
+
+static int
+untrap_error(void)
+{
+ XSetErrorHandler(old_error_handler);
+ if(trapped_error_code) {
+#ifdef DEBUG_XTBIN
+ printf("Get X Window Error = %d\n", trapped_error_code);
+#endif
+ }
+ return trapped_error_code;
+}
+
+static void
+xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event)
+{
+ Display *dpy = XtDisplay(w);
+ XtClient *xtclient = user_data;
+ Window win = XtWindow(w);
+
+ switch(event->type)
+ {
+ case CreateNotify:
+ if(event->xcreatewindow.parent == win) {
+ Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window);
+ if (child)
+ xt_add_focus_listener_tree(child, user_data);
+ }
+ break;
+ case DestroyNotify:
+ xt_remove_focus_listener( w, user_data);
+ break;
+ case ReparentNotify:
+ if(event->xreparent.parent == win) {
+ /* I am the new parent */
+ Widget child=XtWindowToWidget(dpy, event->xreparent.window);
+ if (child)
+ xt_add_focus_listener_tree( child, user_data);
+ }
+ else if(event->xreparent.window == win) {
+ /* I am the new child */
+ }
+ else {
+ /* I am the old parent */
+ }
+ break;
+ case ButtonRelease:
+#if 0
+ XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time);
+#endif
+ send_xembed_message ( xtclient,
+ XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
+ break;
+ default:
+ break;
+ } /* End of switch(event->type) */
+}
+
+static void
+xt_add_focus_listener( Widget w, XtPointer user_data)
+{
+ XWindowAttributes attr;
+ long eventmask;
+ XtClient *xtclient = user_data;
+
+ trap_errors ();
+ XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attr);
+ eventmask = attr.your_event_mask | SubstructureNotifyMask | ButtonReleaseMask;
+ XSelectInput(XtDisplay(w),
+ XtWindow(w),
+ eventmask);
+
+ XtAddEventHandler(w,
+ SubstructureNotifyMask | ButtonReleaseMask,
+ TRUE,
+ (XtEventHandler)xt_client_focus_listener,
+ xtclient);
+ untrap_error();
+}
+
+static void
+xt_remove_focus_listener(Widget w, XtPointer user_data)
+{
+ trap_errors ();
+ XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, TRUE,
+ (XtEventHandler)xt_client_focus_listener, user_data);
+
+ untrap_error();
+}
+
+static void
+xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data)
+{
+ Window win = XtWindow(treeroot);
+ Window *children;
+ Window root, parent;
+ Display *dpy = XtDisplay(treeroot);
+ unsigned int i, nchildren;
+
+ /* ensure we don't add more than once */
+ xt_remove_focus_listener( treeroot, user_data);
+ xt_add_focus_listener( treeroot, user_data);
+ trap_errors();
+ if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
+ untrap_error();
+ return;
+ }
+
+ if(untrap_error())
+ return;
+
+ for(i=0; i<nchildren; ++i) {
+ Widget child = XtWindowToWidget(dpy, children[i]);
+ if (child)
+ xt_add_focus_listener_tree( child, user_data);
+ }
+ XFree((void*)children);
+
+ return;
+}
diff --git a/Source/WebCore/plugins/gtk/gtk2xtbin.h b/Source/WebCore/plugins/gtk/gtk2xtbin.h
new file mode 100644
index 0000000..11f6e06
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/gtk2xtbin.h
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set expandtab shiftwidth=2 tabstop=2: */
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Gtk2XtBin Widget Implementation.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __GTK_XTBIN_H__
+#define __GTK_XTBIN_H__
+
+#include <gtk/gtk.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xutil.h>
+#include <X11/Xlib.h>
+#ifdef MOZILLA_CLIENT
+#include "nscore.h"
+#ifdef _IMPL_GTKXTBIN_API
+#define GTKXTBIN_API(type) NS_EXPORT_(type)
+#else
+#define GTKXTBIN_API(type) NS_IMPORT_(type)
+#endif
+#else
+#define GTKXTBIN_API(type) type
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _GtkXtBin GtkXtBin;
+typedef struct _GtkXtBinClass GtkXtBinClass;
+
+#define GTK_TYPE_XTBIN (gtk_xtbin_get_type ())
+#define GTK_XTBIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ GTK_TYPE_XTBIN, GtkXtBin))
+#define GTK_XTBIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ GTK_TYPE_XTBIN, GtkXtBinClass))
+#define GTK_IS_XTBIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ GTK_TYPE_XTBIN))
+#define GTK_IS_XTBIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ GTK_TYPE_XTBIN))
+typedef struct _XtClient XtClient;
+
+struct _XtClient {
+ Display *xtdisplay;
+ Widget top_widget; /* The toplevel widget */
+ Widget child_widget; /* The embedded widget */
+ Visual *xtvisual;
+ int xtdepth;
+ Colormap xtcolormap;
+ Window oldwindow;
+};
+
+struct _GtkXtBin
+{
+ GtkSocket gsocket;
+ GdkWindow *parent_window;
+ Display *xtdisplay; /* Xt Toolkit Display */
+
+ Window xtwindow; /* Xt Toolkit XWindow */
+ gint x, y;
+ gint width, height;
+ XtClient xtclient; /* Xt Client for XEmbed */
+};
+
+struct _GtkXtBinClass
+{
+ GtkSocketClass widget_class;
+};
+
+GTKXTBIN_API(GType) gtk_xtbin_get_type (void);
+GTKXTBIN_API(GtkWidget *) gtk_xtbin_new (GtkWidget *parent_widget, String *f);
+GTKXTBIN_API(void) gtk_xtbin_set_position (GtkXtBin *xtbin,
+ gint x,
+ gint y);
+GTKXTBIN_API(void) gtk_xtbin_resize (GtkWidget *widget,
+ gint width,
+ gint height);
+
+typedef struct _XtTMRec {
+ XtTranslations translations; /* private to Translation Manager */
+ XtBoundActions proc_table; /* procedure bindings for actions */
+ struct _XtStateRec *current_state; /* Translation Manager state ptr */
+ unsigned long lastEventTime;
+} XtTMRec, *XtTM;
+
+typedef struct _CorePart {
+ Widget self; /* pointer to widget itself */
+ WidgetClass widget_class; /* pointer to Widget's ClassRec */
+ Widget parent; /* parent widget */
+ XrmName xrm_name; /* widget resource name quarkified */
+ Boolean being_destroyed; /* marked for destroy */
+ XtCallbackList destroy_callbacks; /* who to call when widget destroyed */
+ XtPointer constraints; /* constraint record */
+ Position x, y; /* window position */
+ Dimension width, height; /* window dimensions */
+ Dimension border_width; /* window border width */
+ Boolean managed; /* is widget geometry managed? */
+ Boolean sensitive; /* is widget sensitive to user events*/
+ Boolean ancestor_sensitive; /* are all ancestors sensitive? */
+ XtEventTable event_table; /* private to event dispatcher */
+ XtTMRec tm; /* translation management */
+ XtTranslations accelerators; /* accelerator translations */
+ Pixel border_pixel; /* window border pixel */
+ Pixmap border_pixmap; /* window border pixmap or NULL */
+ WidgetList popup_list; /* list of popups */
+ Cardinal num_popups; /* how many popups */
+ String name; /* widget resource name */
+ Screen *screen; /* window's screen */
+ Colormap colormap; /* colormap */
+ Window window; /* window ID */
+ Cardinal depth; /* number of planes in window */
+ Pixel background_pixel; /* window background pixel */
+ Pixmap background_pixmap; /* window background pixmap or NULL */
+ Boolean visible; /* is window mapped and not occluded?*/
+ Boolean mapped_when_managed;/* map window if it's managed? */
+} CorePart;
+
+typedef struct _WidgetRec {
+ CorePart core;
+ } WidgetRec, CoreRec;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __GTK_XTBIN_H__ */
diff --git a/Source/WebCore/plugins/gtk/xembed.h b/Source/WebCore/plugins/gtk/xembed.h
new file mode 100644
index 0000000..dff7be9
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/xembed.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim:expandtab:shiftwidth=2:tabstop=2: */
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the XEMBED Declaration.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* XEMBED messages */
+#define XEMBED_EMBEDDED_NOTIFY 0
+#define XEMBED_WINDOW_ACTIVATE 1
+#define XEMBED_WINDOW_DEACTIVATE 2
+#define XEMBED_REQUEST_FOCUS 3
+#define XEMBED_FOCUS_IN 4
+#define XEMBED_FOCUS_OUT 5
+#define XEMBED_FOCUS_NEXT 6
+#define XEMBED_FOCUS_PREV 7
+#define XEMBED_GRAB_KEY 8
+#define XEMBED_UNGRAB_KEY 9
+#define XEMBED_MODALITY_ON 10
+#define XEMBED_MODALITY_OFF 11
+
+/* Non standard messages*/
+#define XEMBED_GTK_GRAB_KEY 108
+#define XEMBED_GTK_UNGRAB_KEY 109
+
+/* Details for XEMBED_FOCUS_IN: */
+#define XEMBED_FOCUS_CURRENT 0
+#define XEMBED_FOCUS_FIRST 1
+#define XEMBED_FOCUS_LAST 2
+
+/* Flags for _XEMBED_INFO */
+#define XEMBED_MAPPED (1 << 0)
diff --git a/Source/WebCore/plugins/mac/PluginPackageMac.cpp b/Source/WebCore/plugins/mac/PluginPackageMac.cpp
new file mode 100644
index 0000000..865ea32
--- /dev/null
+++ b/Source/WebCore/plugins/mac/PluginPackageMac.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 <wtf/RetainPtr.h>
+#include "MIMETypeRegistry.h"
+#include "npruntime_impl.h"
+#include "PluginDatabase.h"
+#include "PluginDebug.h"
+#include "WebCoreNSStringExtras.h"
+#include <wtf/text/CString.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#define PluginNameOrDescriptionStringNumber 126
+#define MIMEDescriptionStringNumber 127
+#define MIMEListStringStringNumber 128
+
+namespace WebCore {
+
+void PluginPackage::determineQuirks(const String& mimeType)
+{
+ 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 == "application/x-shockwave-flash") {
+ // The flash plugin only requests windowless plugins if we return a mozilla user agent
+ m_quirks.add(PluginQuirkWantsMozillaUserAgent);
+ m_quirks.add(PluginQuirkThrottleInvalidate);
+ m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages);
+ m_quirks.add(PluginQuirkFlashURLNotifyBug);
+ }
+
+}
+
+typedef void (*BP_CreatePluginMIMETypesPreferencesFuncPtr)(void);
+
+static WTF::RetainPtr<CFDictionaryRef> readPListFile(CFStringRef fileName, bool createFile, CFBundleRef bundle)
+{
+ if (createFile) {
+ BP_CreatePluginMIMETypesPreferencesFuncPtr funcPtr =
+ (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("BP_CreatePluginMIMETypesPreferences"));
+ if (funcPtr)
+ funcPtr();
+ }
+
+ WTF::RetainPtr<CFDictionaryRef> map;
+ WTF::RetainPtr<CFURLRef> url =
+ CFURLCreateWithFileSystemPath(kCFAllocatorDefault, fileName, kCFURLPOSIXPathStyle, false);
+
+ CFDataRef resource = 0;
+ SInt32 code;
+ if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url.get(), &resource, 0, 0, &code))
+ return map;
+
+ WTF::RetainPtr<CFPropertyListRef> propertyList =
+ CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource, kCFPropertyListImmutable, 0);
+
+ CFRelease(resource);
+
+ if (!propertyList)
+ return map;
+
+ if (CFGetTypeID(propertyList.get()) != CFDictionaryGetTypeID())
+ return map;
+
+ map = static_cast<CFDictionaryRef>(static_cast<CFPropertyListRef>(propertyList.get()));
+ return map;
+}
+
+static Vector<String> stringListFromResourceId(SInt16 id)
+{
+ Vector<String> list;
+
+ Handle handle = Get1Resource('STR#', id);
+ if (!handle)
+ return list;
+
+ CFStringEncoding encoding = stringEncodingForResource(handle);
+
+ unsigned char* p = (unsigned char*)*handle;
+ if (!p)
+ return list;
+
+ SInt16 count = *(SInt16*)p;
+ p += sizeof(SInt16);
+
+ for (SInt16 i = 0; i < count; ++i) {
+ unsigned char length = *p;
+ WTF::RetainPtr<CFStringRef> str = CFStringCreateWithPascalString(0, p, encoding);
+ list.append(str.get());
+ p += 1 + length;
+ }
+
+ return list;
+}
+
+bool PluginPackage::fetchInfo()
+{
+ if (!load())
+ return false;
+
+ WTF::RetainPtr<CFDictionaryRef> mimeDict;
+
+ WTF::RetainPtr<CFTypeRef> mimeTypesFileName = CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypesFilename"));
+ if (mimeTypesFileName && CFGetTypeID(mimeTypesFileName.get()) == CFStringGetTypeID()) {
+
+ WTF::RetainPtr<CFStringRef> fileName = (CFStringRef)mimeTypesFileName.get();
+ WTF::RetainPtr<CFStringRef> homeDir = homeDirectoryPath().createCFString();
+ WTF::RetainPtr<CFStringRef> path = CFStringCreateWithFormat(0, 0, CFSTR("%@/Library/Preferences/%@"), homeDir.get(), fileName.get());
+
+ WTF::RetainPtr<CFDictionaryRef> plist = readPListFile(path.get(), /*createFile*/ false, m_module);
+ if (plist) {
+ // If the plist isn't localized, have the plug-in recreate it in the preferred language.
+ WTF::RetainPtr<CFStringRef> localizationName =
+ (CFStringRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginLocalizationName"));
+ CFLocaleRef locale = CFLocaleCopyCurrent();
+ if (localizationName != CFLocaleGetIdentifier(locale))
+ plist = readPListFile(path.get(), /*createFile*/ true, m_module);
+
+ CFRelease(locale);
+ } else {
+ // Plist doesn't exist, ask the plug-in to create it.
+ plist = readPListFile(path.get(), /*createFile*/ true, m_module);
+ }
+
+ if (plist)
+ mimeDict = (CFDictionaryRef)CFDictionaryGetValue(plist.get(), CFSTR("WebPluginMIMETypes"));
+ }
+
+ if (!mimeDict)
+ mimeDict = (CFDictionaryRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginMIMETypes"));
+
+ if (mimeDict) {
+ CFIndex propCount = CFDictionaryGetCount(mimeDict.get());
+ Vector<const void*, 128> keys(propCount);
+ Vector<const void*, 128> values(propCount);
+ CFDictionaryGetKeysAndValues(mimeDict.get(), keys.data(), values.data());
+ for (int i = 0; i < propCount; ++i) {
+ String mimeType = (CFStringRef)keys[i];
+ mimeType = mimeType.lower();
+
+ WTF::RetainPtr<CFDictionaryRef> extensionsDict = (CFDictionaryRef)values[i];
+
+ WTF::RetainPtr<CFNumberRef> enabled = (CFNumberRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeEnabled"));
+ if (enabled) {
+ int enabledValue = 0;
+ if (CFNumberGetValue(enabled.get(), kCFNumberIntType, &enabledValue) && enabledValue == 0)
+ continue;
+ }
+
+ Vector<String> mimeExtensions;
+ WTF::RetainPtr<CFArrayRef> extensions = (CFArrayRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginExtensions"));
+ if (extensions) {
+ CFIndex extensionCount = CFArrayGetCount(extensions.get());
+ for (CFIndex i = 0; i < extensionCount; ++i) {
+ String extension =(CFStringRef)CFArrayGetValueAtIndex(extensions.get(), i);
+ extension = extension.lower();
+ mimeExtensions.append(extension);
+ }
+ }
+ m_mimeToExtensions.set(mimeType, mimeExtensions);
+
+ String description = (CFStringRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeDescription"));
+ m_mimeToDescriptions.set(mimeType, description);
+ }
+
+ m_name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginName"));
+ m_description = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginDescription"));
+
+ } else {
+ int resFile = CFBundleOpenBundleResourceMap(m_module);
+
+ UseResFile(resFile);
+
+ Vector<String> mimes = stringListFromResourceId(MIMEListStringStringNumber);
+
+ if (mimes.size() % 2 != 0)
+ return false;
+
+ Vector<String> descriptions = stringListFromResourceId(MIMEDescriptionStringNumber);
+ if (descriptions.size() != mimes.size() / 2)
+ return false;
+
+ for (size_t i = 0; i < mimes.size(); i += 2) {
+ String mime = mimes[i].lower();
+ Vector<String> extensions;
+ mimes[i + 1].lower().split(UChar(','), extensions);
+
+ m_mimeToExtensions.set(mime, extensions);
+
+ m_mimeToDescriptions.set(mime, descriptions[i / 2]);
+ }
+
+ Vector<String> names = stringListFromResourceId(PluginNameOrDescriptionStringNumber);
+ if (names.size() == 2) {
+ m_description = names[0];
+ m_name = names[1];
+ }
+
+ CFBundleCloseBundleResourceMap(m_module, resFile);
+ }
+
+ LOG(Plugins, "PluginPackage::fetchInfo(): Found plug-in '%s'", m_name.utf8().data());
+ if (isPluginBlacklisted()) {
+ LOG(Plugins, "\tPlug-in is blacklisted!");
+ return false;
+ }
+
+ return true;
+}
+
+bool PluginPackage::isPluginBlacklisted()
+{
+ return false;
+}
+
+bool PluginPackage::load()
+{
+ if (m_isLoaded) {
+ m_loadCount++;
+ return true;
+ }
+
+ WTF::RetainPtr<CFStringRef> path(AdoptCF, m_path.createCFString());
+ WTF::RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(),
+ kCFURLPOSIXPathStyle, false));
+ m_module = CFBundleCreate(NULL, url.get());
+ if (!m_module || !CFBundleLoadExecutable(m_module)) {
+ LOG(Plugins, "%s not loaded", m_path.utf8().data());
+ return false;
+ }
+
+ m_isLoaded = true;
+
+ NP_GetEntryPointsFuncPtr NP_GetEntryPoints = 0;
+ NP_InitializeFuncPtr NP_Initialize;
+ NPError npErr;
+
+ NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_Initialize"));
+ NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("NP_GetEntryPoints"));
+ m_NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(m_module, CFSTR("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);
+
+ initializeBrowserFuncs();
+
+ npErr = NP_Initialize(&m_browserFuncs);
+ LOG_NPERROR(npErr);
+ if (npErr != NPERR_NO_ERROR)
+ goto abort;
+
+ npErr = NP_GetEntryPoints(&m_pluginFuncs);
+ LOG_NPERROR(npErr);
+ if (npErr != NPERR_NO_ERROR)
+ goto abort;
+
+ m_loadCount++;
+ return true;
+
+abort:
+ unloadWithoutShutdown();
+ return false;
+}
+
+uint16_t PluginPackage::NPVersion() const
+{
+ return NP_VERSION_MINOR;
+}
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/mac/PluginViewMac.mm b/Source/WebCore/plugins/mac/PluginViewMac.mm
new file mode 100644
index 0000000..7119f0d
--- /dev/null
+++ b/Source/WebCore/plugins/mac/PluginViewMac.mm
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ *
+ * 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 "Bridge.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "FrameTree.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HostWindow.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
+#include "Image.h"
+#include "JSDOMBinding.h"
+#include "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformKeyboardEvent.h"
+#include "PluginDebug.h"
+#include "PluginPackage.h"
+#include "PluginMainThreadScheduler.h"
+#include "RenderLayer.h"
+#include "ScriptController.h"
+#include "Settings.h"
+#include "npruntime_impl.h"
+#include "runtime_root.h"
+#include <runtime/JSLock.h>
+#include <runtime/JSValue.h>
+#include <wtf/RetainPtr.h>
+
+
+using JSC::ExecState;
+using JSC::Interpreter;
+using JSC::JSLock;
+using JSC::JSObject;
+using JSC::JSValue;
+using JSC::UString;
+
+#if PLATFORM(QT)
+#include <QWidget>
+#include <QKeyEvent>
+#include <QPainter>
+#include "QWebPageClient.h"
+QT_BEGIN_NAMESPACE
+extern Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget* w);
+QT_END_NAMESPACE
+#endif
+
+#if PLATFORM(WX)
+#include <wx/defs.h>
+#include <wx/wx.h>
+#endif
+
+using std::min;
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#ifndef NP_NO_CARBON
+static int modifiersForEvent(UIEventWithKeyState *event);
+#endif
+
+static inline WindowRef nativeWindowFor(PlatformWidget widget)
+{
+#if PLATFORM(QT)
+ if (widget)
+#if QT_MAC_USE_COCOA
+ return static_cast<WindowRef>([qt_mac_window_for(widget) windowRef]);
+#else
+ return static_cast<WindowRef>(qt_mac_window_for(widget));
+#endif
+#elif PLATFORM(WX)
+ if (widget)
+ return (WindowRef)widget->MacGetTopLevelWindowRef();
+#endif
+ return 0;
+}
+
+static inline CGContextRef cgHandleFor(PlatformWidget widget)
+{
+#if PLATFORM(QT)
+ if (widget)
+ return (CGContextRef)widget->macCGHandle();
+#endif
+#if PLATFORM(WX)
+ if (widget)
+ return (CGContextRef)widget->MacGetCGContextRef();
+#endif
+ return 0;
+}
+
+static inline IntPoint topLevelOffsetFor(PlatformWidget widget)
+{
+#if PLATFORM(QT)
+ if (widget) {
+ PlatformWidget topLevel = widget->window();
+ return widget->mapTo(topLevel, QPoint(0, 0)) + topLevel->geometry().topLeft() - topLevel->pos();
+ }
+#endif
+#if PLATFORM(WX)
+ if (widget) {
+ PlatformWidget toplevel = wxGetTopLevelParent(widget);
+ return toplevel->ScreenToClient(widget->GetScreenPosition());
+ }
+#endif
+ return IntPoint();
+}
+
+// --------------- Lifetime management -----------------
+
+bool PluginView::platformStart()
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_status == PluginStatusLoadedSuccessfully);
+
+ if (m_drawingModel == NPDrawingModel(-1)) {
+ // We default to QuickDraw, even though we don't support it,
+ // since that's what Safari does, and some plugins expect this
+ // behavior and never set the drawing model explicitly.
+#ifndef NP_NO_QUICKDRAW
+ m_drawingModel = NPDrawingModelQuickDraw;
+#else
+ // QuickDraw not available, so we have to default to CoreGraphics
+ m_drawingModel = NPDrawingModelCoreGraphics;
+#endif
+ }
+
+ if (m_eventModel == NPEventModel(-1)) {
+ // If the plug-in did not specify an event model
+ // we default to Carbon, when it is available.
+#ifndef NP_NO_CARBON
+ m_eventModel = NPEventModelCarbon;
+#else
+ m_eventModel = NPEventModelCocoa;
+#endif
+ }
+
+ // Gracefully handle unsupported drawing or event models. We can do this
+ // now since the drawing and event model can only be set during NPP_New.
+#ifndef NP_NO_CARBON
+ NPBool eventModelSupported;
+ if (getValueStatic(NPNVariable(NPNVsupportsCarbonBool + m_eventModel), &eventModelSupported) != NPERR_NO_ERROR
+ || !eventModelSupported) {
+#endif
+ m_status = PluginStatusCanNotLoadPlugin;
+ LOG(Plugins, "Plug-in '%s' uses unsupported event model %s",
+ m_plugin->name().utf8().data(), prettyNameForEventModel(m_eventModel));
+ return false;
+#ifndef NP_NO_CARBON
+ }
+#endif
+
+#ifndef NP_NO_QUICKDRAW
+ NPBool drawingModelSupported;
+ if (getValueStatic(NPNVariable(NPNVsupportsQuickDrawBool + m_drawingModel), &drawingModelSupported) != NPERR_NO_ERROR
+ || !drawingModelSupported) {
+#endif
+ m_status = PluginStatusCanNotLoadPlugin;
+ LOG(Plugins, "Plug-in '%s' uses unsupported drawing model %s",
+ m_plugin->name().utf8().data(), prettyNameForDrawingModel(m_drawingModel));
+ return false;
+#ifndef NP_NO_QUICKDRAW
+ }
+#endif
+
+#if PLATFORM(QT)
+ // Set the platformPluginWidget only in the case of QWebView so that the context menu appears in the right place.
+ // In all other cases, we use off-screen rendering
+ if (QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient()) {
+ if (QWidget* widget = qobject_cast<QWidget*>(client->pluginParent()))
+ setPlatformPluginWidget(widget);
+ }
+#endif
+#if PLATFORM(WX)
+ if (wxWindow* widget = m_parentFrame->view()->hostWindow()->platformPageClient())
+ setPlatformPluginWidget(widget);
+#endif
+
+ // Create a fake window relative to which all events will be sent when using offscreen rendering
+ if (!platformPluginWidget()) {
+#ifndef NP_NO_CARBON
+ // Make the default size really big. It is unclear why this is required but with a smaller size, mouse move
+ // events don't get processed. Resizing the fake window to flash's size doesn't help.
+ ::Rect windowBounds = { 0, 0, 1000, 1000 };
+ CreateNewWindow(kDocumentWindowClass, kWindowStandardDocumentAttributes, &windowBounds, &m_fakeWindow);
+ // Flash requires the window to be hilited to process mouse move events.
+ HiliteWindow(m_fakeWindow, true);
+#endif
+ }
+
+ updatePluginWidget();
+
+ if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))
+ setNPWindowIfNeeded();
+
+ // TODO: Implement null timer throttling depending on plugin activation
+ m_nullEventTimer.set(new Timer<PluginView>(this, &PluginView::nullEventTimerFired));
+ m_nullEventTimer->startRepeating(0.02);
+
+ m_lastMousePos.h = m_lastMousePos.v = 0;
+
+ return true;
+}
+
+void PluginView::platformDestroy()
+{
+ if (platformPluginWidget())
+ setPlatformPluginWidget(0);
+ else {
+ CGContextRelease(m_contextRef);
+#ifndef NP_NO_CARBON
+ if (m_fakeWindow)
+ DisposeWindow(m_fakeWindow);
+#endif
+ }
+}
+
+// Used before the plugin view has been initialized properly, and as a
+// fallback for variables that do not require a view to resolve.
+bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
+{
+ switch (variable) {
+ case NPNVToolkit:
+ *static_cast<uint32_t*>(value) = 0;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVjavascriptEnabledBool:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+#ifndef NP_NO_CARBON
+ case NPNVsupportsCarbonBool:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+#endif
+ case NPNVsupportsCocoaBool:
+ *static_cast<NPBool*>(value) = false;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ // CoreGraphics is the only drawing model we support
+ case NPNVsupportsCoreGraphicsBool:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+#ifndef NP_NO_QUICKDRAW
+ // QuickDraw is deprecated in 10.5 and not supported on 64-bit
+ case NPNVsupportsQuickDrawBool:
+#endif
+ case NPNVsupportsOpenGLBool:
+ case NPNVsupportsCoreAnimationBool:
+ *static_cast<NPBool*>(value) = false;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+// Used only for variables that need a view to resolve
+bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* error)
+{
+ return false;
+}
+
+void PluginView::setParent(ScrollView* parent)
+{
+ LOG(Plugins, "PluginView::setParent(%p)", parent);
+
+ Widget::setParent(parent);
+
+ if (parent)
+ init();
+}
+
+// -------------- Geometry and painting ----------------
+
+void PluginView::show()
+{
+ LOG(Plugins, "PluginView::show()");
+
+ setSelfVisible(true);
+
+ Widget::show();
+}
+
+void PluginView::hide()
+{
+ LOG(Plugins, "PluginView::hide()");
+
+ setSelfVisible(false);
+
+ Widget::hide();
+}
+
+void PluginView::setFocus(bool focused)
+{
+ LOG(Plugins, "PluginView::setFocus(%d)", focused);
+ if (!focused) {
+ Widget::setFocus(focused);
+ return;
+ }
+
+ if (platformPluginWidget())
+#if PLATFORM(QT)
+ platformPluginWidget()->setFocus(Qt::OtherFocusReason);
+#else
+ platformPluginWidget()->SetFocus();
+#endif
+ else
+ Widget::setFocus(focused);
+
+ // TODO: Also handle and pass on blur events (focus lost)
+
+#ifndef NP_NO_CARBON
+ EventRecord record;
+ record.what = NPEventType_GetFocusEvent;
+ record.message = 0;
+ record.when = TickCount();
+ record.where = globalMousePosForPlugin();
+ record.modifiers = GetCurrentKeyModifiers();
+
+ if (!dispatchNPEvent(record))
+ LOG(Events, "PluginView::setFocus(%d): Focus event not accepted", focused);
+#endif
+}
+
+void PluginView::setParentVisible(bool visible)
+{
+ if (isParentVisible() == visible)
+ return;
+
+ Widget::setParentVisible(visible);
+}
+
+void PluginView::setNPWindowRect(const IntRect&)
+{
+ setNPWindowIfNeeded();
+}
+
+void PluginView::setNPWindowIfNeeded()
+{
+ if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
+ return;
+
+ CGContextRef newContextRef = 0;
+ WindowRef newWindowRef = 0;
+ if (platformPluginWidget()) {
+ newContextRef = cgHandleFor(platformPluginWidget());
+ newWindowRef = nativeWindowFor(platformPluginWidget());
+ m_npWindow.type = NPWindowTypeWindow;
+ } else {
+ newContextRef = m_contextRef;
+ newWindowRef = m_fakeWindow;
+ m_npWindow.type = NPWindowTypeDrawable;
+ }
+
+ if (!newContextRef || !newWindowRef)
+ return;
+
+ m_npWindow.window = (void*)&m_npCgContext;
+#ifndef NP_NO_CARBON
+ m_npCgContext.window = newWindowRef;
+#endif
+ m_npCgContext.context = newContextRef;
+
+ m_npWindow.x = m_windowRect.x();
+ m_npWindow.y = m_windowRect.y();
+ m_npWindow.width = m_windowRect.width();
+ m_npWindow.height = m_windowRect.height();
+
+ // TODO: (also clip against scrollbars, etc.)
+ m_npWindow.clipRect.left = max(0, m_windowRect.x());
+ m_npWindow.clipRect.top = max(0, m_windowRect.y());
+ m_npWindow.clipRect.right = m_windowRect.x() + m_windowRect.width();
+ m_npWindow.clipRect.bottom = m_windowRect.y() + m_windowRect.height();
+
+ LOG(Plugins, "PluginView::setNPWindowIfNeeded(): window=%p, context=%p,"
+ " window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d",
+ newWindowRef, newContextRef, m_npWindow.x, m_npWindow.y, m_npWindow.width, m_npWindow.height,
+ m_npWindow.clipRect.right - m_npWindow.clipRect.left, m_npWindow.clipRect.bottom - m_npWindow.clipRect.top);
+
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+}
+
+void PluginView::updatePluginWidget()
+{
+ if (!parent())
+ return;
+
+ ASSERT(parent()->isFrameView());
+ FrameView* frameView = static_cast<FrameView*>(parent());
+
+ IntRect oldWindowRect = m_windowRect;
+ IntRect oldClipRect = m_clipRect;
+
+ m_windowRect = frameView->contentsToWindow(frameRect());
+ IntPoint offset = topLevelOffsetFor(platformPluginWidget());
+ m_windowRect.move(offset.x(), offset.y());
+
+ if (!platformPluginWidget()) {
+ if (m_windowRect.size() != oldWindowRect.size()) {
+ CGContextRelease(m_contextRef);
+#if PLATFORM(QT)
+ m_pixmap = QPixmap(m_windowRect.size());
+ m_pixmap.fill(Qt::transparent);
+ m_contextRef = m_pixmap.isNull() ? 0 : qt_mac_cg_context(&m_pixmap);
+#endif
+ }
+ }
+
+ m_clipRect = windowClipRect();
+ m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
+
+ if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect))
+ setNPWindowIfNeeded();
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_isStarted || m_status != PluginStatusLoadedSuccessfully) {
+ paintMissingPluginIcon(context, rect);
+ return;
+ }
+
+ if (context->paintingDisabled())
+ return;
+
+ setNPWindowIfNeeded();
+
+ CGContextRef cgContext = m_npCgContext.context;
+ if (!cgContext)
+ return;
+
+ CGContextSaveGState(cgContext);
+ if (platformPluginWidget()) {
+ IntPoint offset = frameRect().location();
+ CGContextTranslateCTM(cgContext, offset.x(), offset.y());
+ }
+
+ IntRect targetRect(frameRect());
+ targetRect.intersects(rect);
+
+ // clip the context so that plugin only updates the interested area.
+ CGRect r;
+ r.origin.x = targetRect.x() - frameRect().x();
+ r.origin.y = targetRect.y() - frameRect().y();
+ r.size.width = targetRect.width();
+ r.size.height = targetRect.height();
+ CGContextClipToRect(cgContext, r);
+
+ if (!platformPluginWidget() && m_isTransparent) { // clean the pixmap in transparent mode
+#if PLATFORM(QT)
+ QPainter painter(&m_pixmap);
+ painter.setCompositionMode(QPainter::CompositionMode_Clear);
+ painter.fillRect(QRectF(r.origin.x, r.origin.y, r.size.width, r.size.height), Qt::transparent);
+#endif
+ }
+
+#ifndef NP_NO_CARBON
+ EventRecord event;
+ event.what = updateEvt;
+ event.message = (long unsigned int)m_npCgContext.window;
+ event.when = TickCount();
+ event.where.h = 0;
+ event.where.v = 0;
+ event.modifiers = GetCurrentKeyModifiers();
+
+ if (!dispatchNPEvent(event))
+ LOG(Events, "PluginView::paint(): Paint event not accepted");
+#endif
+
+ CGContextRestoreGState(cgContext);
+
+ if (!platformPluginWidget()) {
+#if PLATFORM(QT)
+ QPainter* painter = context->platformContext();
+ painter->drawPixmap(targetRect.x(), targetRect.y(), m_pixmap,
+ targetRect.x() - frameRect().x(), targetRect.y() - frameRect().y(), targetRect.width(), targetRect.height());
+#endif
+ }
+}
+
+void PluginView::invalidateRect(const IntRect& rect)
+{
+ if (platformPluginWidget())
+#if PLATFORM(QT)
+ platformPluginWidget()->update(convertToContainingWindow(rect));
+#else
+ platformPluginWidget()->RefreshRect(convertToContainingWindow(rect));
+#endif
+ else
+ invalidateWindowlessPluginRect(rect);
+}
+
+void PluginView::invalidateRect(NPRect* rect)
+{
+ IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
+ invalidateRect(r);
+}
+
+void PluginView::invalidateRegion(NPRegion region)
+{
+ // TODO: optimize
+ invalidate();
+}
+
+void PluginView::forceRedraw()
+{
+ notImplemented();
+}
+
+
+// ----------------- Event handling --------------------
+
+void PluginView::handleMouseEvent(MouseEvent* event)
+{
+ if (!m_isStarted)
+ return;
+
+#ifndef NP_NO_CARBON
+ EventRecord record;
+
+ if (event->type() == eventNames().mousemoveEvent) {
+ // Mouse movement is handled by null timer events
+ m_lastMousePos = mousePosForPlugin(event);
+ return;
+ } else if (event->type() == eventNames().mouseoverEvent) {
+ record.what = NPEventType_AdjustCursorEvent;
+ } else if (event->type() == eventNames().mouseoutEvent) {
+ record.what = NPEventType_AdjustCursorEvent;
+ } else if (event->type() == eventNames().mousedownEvent) {
+ record.what = mouseDown;
+ // The plugin needs focus to receive keyboard events
+ if (Page* page = m_parentFrame->page())
+ page->focusController()->setFocusedFrame(m_parentFrame);
+ m_parentFrame->document()->setFocusedNode(m_element);
+ } else if (event->type() == eventNames().mouseupEvent) {
+ record.what = mouseUp;
+ } else {
+ return;
+ }
+ record.where = mousePosForPlugin(event);
+ record.modifiers = modifiersForEvent(event);
+
+ if (!event->buttonDown())
+ record.modifiers |= btnState;
+
+ if (event->button() == 2)
+ record.modifiers |= controlKey;
+
+ if (!dispatchNPEvent(record)) {
+ if (record.what == NPEventType_AdjustCursorEvent)
+ return; // Signals that the plugin wants a normal cursor
+
+ LOG(Events, "PluginView::handleMouseEvent(): Mouse event type %d at %d,%d not accepted",
+ record.what, record.where.h, record.where.v);
+ } else {
+ event->setDefaultHandled();
+ }
+#endif
+}
+
+void PluginView::handleKeyboardEvent(KeyboardEvent* event)
+{
+ if (!m_isStarted)
+ return;
+
+ LOG(Plugins, "PluginView::handleKeyboardEvent() ----------------- ");
+
+ LOG(Plugins, "PV::hKE(): KE.keyCode: 0x%02X, KE.charCode: %d",
+ event->keyCode(), event->charCode());
+
+#ifndef NP_NO_CARBON
+ EventRecord record;
+
+ if (event->type() == eventNames().keydownEvent) {
+ // This event is the result of a PlatformKeyboardEvent::KeyDown which
+ // was disambiguated into a PlatformKeyboardEvent::RawKeyDown. Since
+ // we don't have access to the text here, we return, and wait for the
+ // corresponding event based on PlatformKeyboardEvent::Char.
+ return;
+ } else if (event->type() == eventNames().keypressEvent) {
+ // Which would be this one. This event was disambiguated from the same
+ // PlatformKeyboardEvent::KeyDown, but to a PlatformKeyboardEvent::Char,
+ // which retains the text from the original event. So, we can safely pass
+ // on the event as a key-down event to the plugin.
+ record.what = keyDown;
+ } else if (event->type() == eventNames().keyupEvent) {
+ // PlatformKeyboardEvent::KeyUp events always have the text, so nothing
+ // fancy here.
+ record.what = keyUp;
+ } else {
+ return;
+ }
+
+ const PlatformKeyboardEvent* platformEvent = event->keyEvent();
+ int keyCode = platformEvent->nativeVirtualKeyCode();
+
+ const String text = platformEvent->text();
+ if (text.length() < 1) {
+ event->setDefaultHandled();
+ return;
+ }
+
+ WTF::RetainPtr<CFStringRef> cfText(WTF::AdoptCF, text.createCFString());
+
+ LOG(Plugins, "PV::hKE(): PKE.text: %s, PKE.unmodifiedText: %s, PKE.keyIdentifier: %s",
+ text.ascii().data(), platformEvent->unmodifiedText().ascii().data(),
+ platformEvent->keyIdentifier().ascii().data());
+
+ char charCodes[2] = { 0, 0 };
+ if (!CFStringGetCString(cfText.get(), charCodes, 2, CFStringGetSystemEncoding())) {
+ LOG_ERROR("Could not resolve character code using system encoding.");
+ event->setDefaultHandled();
+ return;
+ }
+
+ record.where = globalMousePosForPlugin();
+ record.modifiers = modifiersForEvent(event);
+ record.message = ((keyCode & 0xFF) << 8) | (charCodes[0] & 0xFF);
+ record.when = TickCount();
+
+ LOG(Plugins, "PV::hKE(): record.modifiers: %d", record.modifiers);
+
+#if PLATFORM(QT)
+ LOG(Plugins, "PV::hKE(): PKE.qtEvent()->nativeVirtualKey: 0x%02X, charCode: %d",
+ keyCode, int(uchar(charCodes[0])));
+#endif
+
+ if (!dispatchNPEvent(record))
+ LOG(Events, "PluginView::handleKeyboardEvent(): Keyboard event type %d not accepted", record.what);
+ else
+ event->setDefaultHandled();
+#endif
+}
+
+#ifndef NP_NO_CARBON
+void PluginView::nullEventTimerFired(Timer<PluginView>*)
+{
+ EventRecord record;
+
+ record.what = nullEvent;
+ record.message = 0;
+ record.when = TickCount();
+ record.where = m_lastMousePos;
+ record.modifiers = GetCurrentKeyModifiers();
+ if (!Button())
+ record.modifiers |= btnState;
+
+ if (!dispatchNPEvent(record))
+ LOG(Events, "PluginView::nullEventTimerFired(): Null event not accepted");
+}
+#endif
+
+#ifndef NP_NO_CARBON
+static int modifiersForEvent(UIEventWithKeyState* event)
+{
+ int modifiers = 0;
+
+ if (event->ctrlKey())
+ modifiers |= controlKey;
+
+ if (event->altKey())
+ modifiers |= optionKey;
+
+ if (event->metaKey())
+ modifiers |= cmdKey;
+
+ if (event->shiftKey())
+ modifiers |= shiftKey;
+
+ return modifiers;
+}
+#endif
+
+#ifndef NP_NO_CARBON
+Point PluginView::globalMousePosForPlugin() const
+{
+ Point pos;
+ GetGlobalMouse(&pos);
+
+#if PLATFORM(WX)
+ // make sure the titlebar/toolbar size is included
+ WindowRef windowRef = nativeWindowFor(platformPluginWidget());
+ ::Rect content, structure;
+
+ GetWindowBounds(windowRef, kWindowStructureRgn, &structure);
+ GetWindowBounds(windowRef, kWindowContentRgn, &content);
+
+ int top = content.top - structure.top;
+ pos.v -= top;
+#endif
+
+ return pos;
+}
+#endif
+
+#ifndef NP_NO_CARBON
+Point PluginView::mousePosForPlugin(MouseEvent* event) const
+{
+ ASSERT(event);
+ if (platformPluginWidget())
+ return globalMousePosForPlugin();
+
+ if (event->button() == 2) {
+ // always pass the global position for right-click since Flash uses it to position the context menu
+ return globalMousePosForPlugin();
+ }
+
+ Point pos;
+ IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
+ pos.h = postZoomPos.x() + m_windowRect.x();
+ // The number 22 is the height of the title bar. As to why it figures in the calculation below
+ // is left as an exercise to the reader :-)
+ pos.v = postZoomPos.y() + m_windowRect.y() - 22;
+ return pos;
+}
+#endif
+
+#ifndef NP_NO_CARBON
+bool PluginView::dispatchNPEvent(NPEvent& event)
+{
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+
+ bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
+
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ return accepted;
+}
+#endif
+
+// ------------------- Miscellaneous ------------------
+
+NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
+{
+ String filename(buf, len);
+
+ if (filename.startsWith("file:///"))
+ filename = filename.substring(8);
+
+ if (!fileExists(filename))
+ return NPERR_FILE_NOT_FOUND;
+
+ FILE* fileHandle = fopen((filename.utf8()).data(), "r");
+
+ if (fileHandle == 0)
+ return NPERR_FILE_NOT_FOUND;
+
+ int bytesRead = fread(buffer.data(), 1, 0, fileHandle);
+
+ fclose(fileHandle);
+
+ if (bytesRead <= 0)
+ return NPERR_FILE_NOT_FOUND;
+
+ return NPERR_NO_ERROR;
+}
+
+void PluginView::halt()
+{
+}
+
+void PluginView::restart()
+{
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/npapi.cpp b/Source/WebCore/plugins/npapi.cpp
new file mode 100644
index 0000000..bc64901
--- /dev/null
+++ b/Source/WebCore/plugins/npapi.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Page.h"
+#include "PluginMainThreadScheduler.h"
+#include "PluginView.h"
+#include "npruntime_internal.h"
+
+using namespace WebCore;
+
+// The plugin view is always the ndata of the instance,. Sometimes, plug-ins will call an instance-specific function
+// with a NULL instance. To workaround this, call the last plug-in view that made a call to a plug-in.
+// Currently, the current plug-in view is only set before NPP_New in PluginView::start.
+// This specifically works around Flash and Shockwave. When we call NPP_New, they call NPN_Useragent with a NULL instance.
+static PluginView* pluginViewForInstance(NPP instance)
+{
+ if (instance && instance->ndata)
+ return static_cast<PluginView*>(instance->ndata);
+ return PluginView::currentPluginView();
+}
+
+void* NPN_MemAlloc(uint32_t size)
+{
+ return malloc(size);
+}
+
+void NPN_MemFree(void* ptr)
+{
+ free(ptr);
+}
+
+uint32_t NPN_MemFlush(uint32_t size)
+{
+ // Do nothing
+ return 0;
+}
+
+void NPN_ReloadPlugins(NPBool reloadPages)
+{
+ Page::refreshPlugins(reloadPages);
+}
+
+NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
+{
+ return NPERR_STREAM_NOT_SEEKABLE;
+}
+
+NPError NPN_GetURLNotify(NPP instance, const char* url, const char* target, void* notifyData)
+{
+ return pluginViewForInstance(instance)->getURLNotify(url, target, notifyData);
+}
+
+NPError NPN_GetURL(NPP instance, const char* url, const char* target)
+{
+ return pluginViewForInstance(instance)->getURL(url, target);
+}
+
+NPError NPN_PostURLNotify(NPP instance, const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData)
+{
+ return pluginViewForInstance(instance)->postURLNotify(url, target, len, buf, file, notifyData);
+}
+
+NPError NPN_PostURL(NPP instance, const char* url, const char* target, uint32_t len, const char* buf, NPBool file)
+{
+ return pluginViewForInstance(instance)->postURL(url, target, len, buf, file);
+}
+
+NPError NPN_NewStream(NPP instance, NPMIMEType type, const char* target, NPStream** stream)
+{
+ return pluginViewForInstance(instance)->newStream(type, target, stream);
+}
+
+int32_t NPN_Write(NPP instance, NPStream* stream, int32_t len, void* buffer)
+{
+ return pluginViewForInstance(instance)->write(stream, len, buffer);
+}
+
+NPError NPN_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
+{
+ return pluginViewForInstance(instance)->destroyStream(stream, reason);
+}
+
+const char* NPN_UserAgent(NPP instance)
+{
+ PluginView* view = pluginViewForInstance(instance);
+
+ if (!view)
+ return PluginView::userAgentStatic();
+
+ return view->userAgent();
+}
+
+void NPN_Status(NPP instance, const char* message)
+{
+ pluginViewForInstance(instance)->status(message);
+}
+
+void NPN_InvalidateRect(NPP instance, NPRect* invalidRect)
+{
+ pluginViewForInstance(instance)->invalidateRect(invalidRect);
+}
+
+void NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion)
+{
+ pluginViewForInstance(instance)->invalidateRegion(invalidRegion);
+}
+
+void NPN_ForceRedraw(NPP instance)
+{
+ pluginViewForInstance(instance)->forceRedraw();
+}
+
+NPError NPN_GetValue(NPP instance, NPNVariable variable, void* value)
+{
+ PluginView* view = pluginViewForInstance(instance);
+
+ if (!view)
+ return PluginView::getValueStatic(variable, value);
+
+ return pluginViewForInstance(instance)->getValue(variable, value);
+}
+
+NPError NPN_SetValue(NPP instance, NPPVariable variable, void* value)
+{
+ return pluginViewForInstance(instance)->setValue(variable, value);
+}
+
+void* NPN_GetJavaEnv()
+{
+ // Unsupported
+ return 0;
+}
+
+void* NPN_GetJavaPeer(NPP instance)
+{
+ // Unsupported
+ return 0;
+}
+
+void NPN_PushPopupsEnabledState(NPP instance, NPBool enabled)
+{
+ pluginViewForInstance(instance)->pushPopupsEnabledState(enabled);
+}
+
+void NPN_PopPopupsEnabledState(NPP instance)
+{
+ pluginViewForInstance(instance)->popPopupsEnabledState();
+}
+
+void NPN_PluginThreadAsyncCall(NPP instance, void (*func) (void *), void *userData)
+{
+ PluginMainThreadScheduler::scheduler().scheduleCall(instance, func, userData);
+}
+
+NPError NPN_GetValueForURL(NPP instance, NPNURLVariable variable, const char* url, char** value, uint32_t* len)
+{
+ return pluginViewForInstance(instance)->getValueForURL(variable, url, value, len);
+}
+
+NPError NPN_SetValueForURL(NPP instance, NPNURLVariable variable, const char* url, const char* value, uint32_t len)
+{
+ return pluginViewForInstance(instance)->setValueForURL(variable, url, value, len);
+}
+
+NPError NPN_GetAuthenticationInfo(NPP instance, const char* protocol, const char* host, int32_t port, const char* scheme, const char* realm, char** username, uint32_t* ulen, char** password, uint32_t* plen)
+{
+ return pluginViewForInstance(instance)->getAuthenticationInfo(protocol, host, port, scheme, realm, username, ulen, password, plen);
+}
+
+#ifdef PLUGIN_SCHEDULE_TIMER
+uint32_t NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat,
+ void (*timerFunc)(NPP npp, uint32_t timerID))
+{
+ return pluginViewForInstance(instance)->scheduleTimer(instance, interval,
+ repeat != 0, timerFunc);
+}
+
+void NPN_UnscheduleTimer(NPP instance, uint32_t timerID)
+{
+ pluginViewForInstance(instance)->unscheduleTimer(instance, timerID);
+}
+#endif
diff --git a/Source/WebCore/plugins/npfunctions.h b/Source/WebCore/plugins/npfunctions.h
new file mode 100644
index 0000000..675ccb9
--- /dev/null
+++ b/Source/WebCore/plugins/npfunctions.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef NPFUNCTIONS_H
+#define NPFUNCTIONS_H
+
+
+#include "npruntime.h"
+#include "npapi.h"
+#if defined(ANDROID_PLUGINS)
+#include "nativehelper/jni.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(XP_WIN)
+#define EXPORTED_CALLBACK(_type, _name) _type (__stdcall * _name)
+#else
+#define EXPORTED_CALLBACK(_type, _name) _type (* _name)
+#endif
+
+typedef NPError (*NPN_GetURLNotifyProcPtr)(NPP instance, const char* URL, const char* window, void* notifyData);
+typedef NPError (*NPN_PostURLNotifyProcPtr)(NPP instance, const char* URL, const char* window, uint32_t len, const char* buf, NPBool file, void* notifyData);
+typedef NPError (*NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList);
+typedef NPError (*NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** stream);
+typedef int32_t (*NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32_t len, void* buffer);
+typedef NPError (*NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
+typedef void (*NPN_StatusProcPtr)(NPP instance, const char* message);
+typedef const char*(*NPN_UserAgentProcPtr)(NPP instance);
+typedef void* (*NPN_MemAllocProcPtr)(uint32_t size);
+typedef void (*NPN_MemFreeProcPtr)(void* ptr);
+typedef uint32_t (*NPN_MemFlushProcPtr)(uint32_t size);
+typedef void (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages);
+typedef NPError (*NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value);
+typedef NPError (*NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value);
+typedef void (*NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect);
+typedef void (*NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region);
+typedef void (*NPN_ForceRedrawProcPtr)(NPP instance);
+typedef NPError (*NPN_GetURLProcPtr)(NPP instance, const char* URL, const char* window);
+typedef NPError (*NPN_PostURLProcPtr)(NPP instance, const char* URL, const char* window, uint32_t len, const char* buf, NPBool file);
+typedef void* (*NPN_GetJavaEnvProcPtr)(void);
+typedef void* (*NPN_GetJavaPeerProcPtr)(NPP instance);
+typedef void (*NPN_PushPopupsEnabledStateProcPtr)(NPP instance, NPBool enabled);
+typedef void (*NPN_PopPopupsEnabledStateProcPtr)(NPP instance);
+typedef void (*NPN_PluginThreadAsyncCallProcPtr)(NPP npp, void (*func)(void *), void *userData);
+typedef NPError (*NPN_GetValueForURLProcPtr)(NPP npp, NPNURLVariable variable, const char* url, char** value, uint32_t* len);
+typedef NPError (*NPN_SetValueForURLProcPtr)(NPP npp, NPNURLVariable variable, const char* url, const char* value, uint32_t len);
+typedef NPError (*NPN_GetAuthenticationInfoProcPtr)(NPP npp, const char* protocol, const char* host, int32_t port, const char* scheme, const char *realm, char** username, uint32_t* ulen, char** password, uint32_t* plen);
+
+typedef uint32_t (*NPN_ScheduleTimerProcPtr)(NPP npp, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
+typedef void (*NPN_UnscheduleTimerProcPtr)(NPP npp, uint32_t timerID);
+typedef NPError (*NPN_PopUpContextMenuProcPtr)(NPP instance, NPMenu* menu);
+typedef NPBool (*NPN_ConvertPointProcPtr)(NPP npp, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
+
+typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant);
+
+typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr) (const NPUTF8 *name);
+typedef void (*NPN_GetStringIdentifiersProcPtr) (const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers);
+typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr) (int32_t intid);
+typedef int32_t (*NPN_IntFromIdentifierProcPtr) (NPIdentifier identifier);
+typedef bool (*NPN_IdentifierIsStringProcPtr) (NPIdentifier identifier);
+typedef NPUTF8 *(*NPN_UTF8FromIdentifierProcPtr) (NPIdentifier identifier);
+
+typedef NPObject* (*NPN_CreateObjectProcPtr) (NPP, NPClass *aClass);
+typedef NPObject* (*NPN_RetainObjectProcPtr) (NPObject *obj);
+typedef void (*NPN_ReleaseObjectProcPtr) (NPObject *obj);
+typedef bool (*NPN_InvokeProcPtr) (NPP npp, NPObject *obj, NPIdentifier methodName, const NPVariant *args, unsigned argCount, NPVariant *result);
+typedef bool (*NPN_InvokeDefaultProcPtr) (NPP npp, NPObject *obj, const NPVariant *args, unsigned argCount, NPVariant *result);
+typedef bool (*NPN_EvaluateProcPtr) (NPP npp, NPObject *obj, NPString *script, NPVariant *result);
+typedef bool (*NPN_GetPropertyProcPtr) (NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result);
+typedef bool (*NPN_SetPropertyProcPtr) (NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value);
+typedef bool (*NPN_HasPropertyProcPtr) (NPP, NPObject *npobj, NPIdentifier propertyName);
+typedef bool (*NPN_HasMethodProcPtr) (NPP npp, NPObject *npobj, NPIdentifier methodName);
+typedef bool (*NPN_RemovePropertyProcPtr) (NPP npp, NPObject *obj, NPIdentifier propertyName);
+typedef void (*NPN_SetExceptionProcPtr) (NPObject *obj, const NPUTF8 *message);
+typedef bool (*NPN_EnumerateProcPtr) (NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count);
+typedef bool (*NPN_ConstructProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
+
+typedef NPError (*NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved);
+typedef NPError (*NPP_DestroyProcPtr)(NPP instance, NPSavedData** save);
+typedef NPError (*NPP_SetWindowProcPtr)(NPP instance, NPWindow* window);
+typedef NPError (*NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype);
+typedef NPError (*NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
+typedef void (*NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname);
+typedef int32_t (*NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream);
+typedef int32_t (*NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer);
+typedef void (*NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint);
+typedef int16_t (*NPP_HandleEventProcPtr)(NPP instance, void* event);
+typedef void (*NPP_URLNotifyProcPtr)(NPP instance, const char* URL, NPReason reason, void* notifyData);
+typedef NPError (*NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value);
+typedef NPError (*NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value);
+
+typedef void *(*NPP_GetJavaClassProcPtr)(void);
+typedef void* JRIGlobalRef; //not using this right now
+
+typedef struct _NPNetscapeFuncs {
+ uint16_t size;
+ uint16_t version;
+
+ NPN_GetURLProcPtr geturl;
+ NPN_PostURLProcPtr posturl;
+ NPN_RequestReadProcPtr requestread;
+ NPN_NewStreamProcPtr newstream;
+ NPN_WriteProcPtr write;
+ NPN_DestroyStreamProcPtr destroystream;
+ NPN_StatusProcPtr status;
+ NPN_UserAgentProcPtr uagent;
+ NPN_MemAllocProcPtr memalloc;
+ NPN_MemFreeProcPtr memfree;
+ NPN_MemFlushProcPtr memflush;
+ NPN_ReloadPluginsProcPtr reloadplugins;
+ NPN_GetJavaEnvProcPtr getJavaEnv;
+ NPN_GetJavaPeerProcPtr getJavaPeer;
+ NPN_GetURLNotifyProcPtr geturlnotify;
+ NPN_PostURLNotifyProcPtr posturlnotify;
+ NPN_GetValueProcPtr getvalue;
+ NPN_SetValueProcPtr setvalue;
+ NPN_InvalidateRectProcPtr invalidaterect;
+ NPN_InvalidateRegionProcPtr invalidateregion;
+ NPN_ForceRedrawProcPtr forceredraw;
+
+ NPN_GetStringIdentifierProcPtr getstringidentifier;
+ NPN_GetStringIdentifiersProcPtr getstringidentifiers;
+ NPN_GetIntIdentifierProcPtr getintidentifier;
+ NPN_IdentifierIsStringProcPtr identifierisstring;
+ NPN_UTF8FromIdentifierProcPtr utf8fromidentifier;
+ NPN_IntFromIdentifierProcPtr intfromidentifier;
+ NPN_CreateObjectProcPtr createobject;
+ NPN_RetainObjectProcPtr retainobject;
+ NPN_ReleaseObjectProcPtr releaseobject;
+ NPN_InvokeProcPtr invoke;
+ NPN_InvokeDefaultProcPtr invokeDefault;
+ NPN_EvaluateProcPtr evaluate;
+ NPN_GetPropertyProcPtr getproperty;
+ NPN_SetPropertyProcPtr setproperty;
+ NPN_RemovePropertyProcPtr removeproperty;
+ NPN_HasPropertyProcPtr hasproperty;
+ NPN_HasMethodProcPtr hasmethod;
+ NPN_ReleaseVariantValueProcPtr releasevariantvalue;
+ NPN_SetExceptionProcPtr setexception;
+ NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate;
+ NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate;
+ NPN_EnumerateProcPtr enumerate;
+ NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall;
+ NPN_ConstructProcPtr construct;
+ NPN_GetValueForURLProcPtr getvalueforurl;
+ NPN_SetValueForURLProcPtr setvalueforurl;
+ NPN_GetAuthenticationInfoProcPtr getauthenticationinfo;
+ NPN_ScheduleTimerProcPtr scheduletimer;
+ NPN_UnscheduleTimerProcPtr unscheduletimer;
+ NPN_PopUpContextMenuProcPtr popupcontextmenu;
+ NPN_ConvertPointProcPtr convertpoint;
+} NPNetscapeFuncs;
+
+typedef struct _NPPluginFuncs {
+ uint16_t size;
+ uint16_t version;
+ NPP_NewProcPtr newp;
+ NPP_DestroyProcPtr destroy;
+ NPP_SetWindowProcPtr setwindow;
+ NPP_NewStreamProcPtr newstream;
+ NPP_DestroyStreamProcPtr destroystream;
+ NPP_StreamAsFileProcPtr asfile;
+ NPP_WriteReadyProcPtr writeready;
+ NPP_WriteProcPtr write;
+ NPP_PrintProcPtr print;
+ NPP_HandleEventProcPtr event;
+ NPP_URLNotifyProcPtr urlnotify;
+ JRIGlobalRef javaClass;
+ NPP_GetValueProcPtr getvalue;
+ NPP_SetValueProcPtr setvalue;
+} NPPluginFuncs;
+
+typedef EXPORTED_CALLBACK(NPError, NP_GetEntryPointsFuncPtr)(NPPluginFuncs*);
+typedef EXPORTED_CALLBACK(void, NPP_ShutdownProcPtr)(void);
+
+#if defined(XP_MACOSX)
+typedef void (*BP_CreatePluginMIMETypesPreferencesFuncPtr)(void);
+typedef NPError (*MainFuncPtr)(NPNetscapeFuncs*, NPPluginFuncs*, NPP_ShutdownProcPtr*);
+#endif
+
+#if defined(XP_UNIX)
+typedef EXPORTED_CALLBACK(NPError, NP_InitializeFuncPtr)(NPNetscapeFuncs*, NPPluginFuncs*);
+typedef EXPORTED_CALLBACK(char*, NP_GetMIMEDescriptionFuncPtr)(void);
+#elif defined(ANDROID_PLUGINS)
+typedef EXPORTED_CALLBACK(NPError, NP_InitializeFuncPtr)(NPNetscapeFuncs*, NPPluginFuncs*, JNIEnv *java_environment);
+typedef EXPORTED_CALLBACK(char*, NP_GetMIMEDescriptionFuncPtr)(void);
+#else
+typedef EXPORTED_CALLBACK(NPError, NP_InitializeFuncPtr)(NPNetscapeFuncs*);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Source/WebCore/plugins/qt/PluginContainerQt.cpp b/Source/WebCore/plugins/qt/PluginContainerQt.cpp
new file mode 100644
index 0000000..8486180
--- /dev/null
+++ b/Source/WebCore/plugins/qt/PluginContainerQt.cpp
@@ -0,0 +1,150 @@
+/*
+ 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.
+*/
+
+#include "config.h"
+#include "PluginContainerQt.h"
+
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "PluginView.h"
+#include <QApplication>
+#include <QX11Info>
+
+using namespace WebCore;
+
+PluginClientWrapper::PluginClientWrapper(QWidget* parent, WId client)
+ : QWidget(0, Qt::Popup)
+{
+ // create a QWidget that adopts the plugin window id, do not give it
+ // a parent so that we don't end up handling events supposed to be
+ // handled by the QX11EmbedContainer.
+
+ // without the parent this will be considered a toplevel widget,
+ // and thus make Qt not quit the event loop after the last window
+ // has been closed. In order to work around this, we set the window
+ // type to Qt::Popup.
+
+ create(client, false, true);
+ m_parent = parent;
+}
+
+PluginClientWrapper::~PluginClientWrapper()
+{
+ destroy(false, false);
+}
+
+bool PluginClientWrapper::x11Event(XEvent* event)
+{
+ // modify the event window id and insert it into the Qt event system.
+ event->xany.window = m_parent->effectiveWinId();
+ static_cast<QApplication*>(QApplication::instance())->x11ProcessEvent(event);
+ return true;
+}
+
+PluginContainerQt::PluginContainerQt(PluginView* view, QWidget* parent)
+ : QX11EmbedContainer(parent)
+ , m_pluginView(view)
+ , m_clientWrapper(0)
+{
+ connect(this, SIGNAL(clientClosed()), this, SLOT(on_clientClosed()));
+ connect(this, SIGNAL(clientIsEmbedded()), this, SLOT(on_clientIsEmbedded()));
+}
+
+PluginContainerQt::~PluginContainerQt()
+{
+ delete m_clientWrapper;
+ m_pluginView->setPlatformPluginWidget(0);
+}
+
+void PluginContainerQt::on_clientClosed()
+{
+ delete m_clientWrapper;
+ m_clientWrapper = 0;
+}
+
+void PluginContainerQt::on_clientIsEmbedded()
+{
+ delete m_clientWrapper;
+ m_clientWrapper = 0;
+
+ // Only create a QWidget wrapper for the plugin in the case it isn't in the
+ // Qt window mapper, and thus receiving events from the Qt event system.
+ // This way the PluginClientWrapper receives the scroll events and passes
+ // them to the parent. NOTICE: Native Qt based plugins running in process,
+ // will already be in the window mapper, and thus creating a wrapper, stops
+ // them from getting events from Qt, as they are redirected to the wrapper.
+ if (!QWidget::find(clientWinId()))
+ m_clientWrapper = new PluginClientWrapper(this, clientWinId());
+}
+
+void PluginContainerQt::redirectWheelEventsToParent(bool enable)
+{
+ // steal wheel events from the plugin as we want to handle it. When doing this
+ // all button 4, 5, 6, and 7, ButtonPress and ButtonRelease events are passed
+ // to the x11Event handler of the PluginClientWrapper, which then changes the
+ // window id of the event to the parent of PluginContainer and puts the event
+ // back into the Qt event loop, so that we will actually scroll the parent
+ // frame.
+ for (int buttonNo = 4; buttonNo < 8; buttonNo++) {
+ if (enable)
+ XGrabButton(x11Info().display(), buttonNo, AnyModifier, clientWinId(),
+ false, ButtonPressMask, GrabModeAsync, GrabModeAsync, 0L, 0L);
+ else
+ XUngrabButton(x11Info().display(), buttonNo, AnyModifier, clientWinId());
+ }
+}
+
+bool PluginContainerQt::x11Event(XEvent* event)
+{
+ switch (event->type) {
+ case EnterNotify:
+ // if the plugin window doesn't have focus we do not want to send wheel
+ // events to it, but to the parent frame, so let's redirect here.
+ redirectWheelEventsToParent(!hasFocus());
+ break;
+ case LeaveNotify:
+ // it is always safe to ungrab wheel events when the mouse leaves the
+ // plugin window.
+ redirectWheelEventsToParent(false);
+ break;
+ }
+
+ return QX11EmbedContainer::x11Event(event);
+}
+
+void PluginContainerQt::focusInEvent(QFocusEvent* event)
+{
+ // we got focus, stop redirecting the wheel events
+ redirectWheelEventsToParent(false);
+
+ if (Page* page = m_pluginView->parentFrame()->page())
+ page->focusController()->setActive(true);
+
+ m_pluginView->focusPluginElement();
+}
+
+void PluginContainerQt::focusOutEvent(QFocusEvent*)
+{
+ if (Page* page = m_pluginView->parentFrame()->page())
+ page->focusController()->setActive(false);
+}
diff --git a/Source/WebCore/plugins/qt/PluginContainerQt.h b/Source/WebCore/plugins/qt/PluginContainerQt.h
new file mode 100644
index 0000000..3a2896d
--- /dev/null
+++ b/Source/WebCore/plugins/qt/PluginContainerQt.h
@@ -0,0 +1,63 @@
+/*
+ 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.
+*/
+#ifndef PluginContainerQt_h
+#define PluginContainerQt_h
+
+#include <QX11EmbedContainer>
+
+namespace WebCore {
+
+ class PluginView;
+
+ class PluginContainerQt : public QX11EmbedContainer
+ {
+ Q_OBJECT
+ public:
+ PluginContainerQt(PluginView*, QWidget* parent);
+ ~PluginContainerQt();
+
+ void redirectWheelEventsToParent(bool enable = true);
+
+ protected:
+ virtual bool x11Event(XEvent*);
+ virtual void focusInEvent(QFocusEvent*);
+ virtual void focusOutEvent(QFocusEvent*);
+
+ public slots:
+ void on_clientClosed();
+ void on_clientIsEmbedded();
+
+ private:
+ PluginView* m_pluginView;
+ QWidget* m_clientWrapper;
+ };
+
+ class PluginClientWrapper : public QWidget
+ {
+ public:
+ PluginClientWrapper(QWidget* parent, WId client);
+ ~PluginClientWrapper();
+ bool x11Event(XEvent*);
+
+ private:
+ QWidget* m_parent;
+ };
+}
+
+#endif // PluginContainerQt_h
diff --git a/Source/WebCore/plugins/qt/PluginPackageQt.cpp b/Source/WebCore/plugins/qt/PluginPackageQt.cpp
new file mode 100644
index 0000000..ce07faf
--- /dev/null
+++ b/Source/WebCore/plugins/qt/PluginPackageQt.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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 "PluginPackage.h"
+
+#include "MIMETypeRegistry.h"
+#include "npruntime_impl.h"
+#include "PluginDatabase.h"
+#include "PluginDebug.h"
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+bool PluginPackage::fetchInfo()
+{
+ if (!load())
+ return false;
+
+ NPP_GetValueProcPtr gv = (NPP_GetValueProcPtr)m_module->resolve("NP_GetValue");
+ typedef char *(*NPP_GetMIMEDescriptionProcPtr)();
+ NPP_GetMIMEDescriptionProcPtr gm =
+ (NPP_GetMIMEDescriptionProcPtr)m_module->resolve("NP_GetMIMEDescription");
+ if (!gm || !gv)
+ return false;
+
+ char *buf = 0;
+ NPError err = gv(0, NPPVpluginNameString, (void*) &buf);
+ if (err != NPERR_NO_ERROR)
+ return false;
+
+ m_name = buf;
+ err = gv(0, NPPVpluginDescriptionString, (void*) &buf);
+ if (err != NPERR_NO_ERROR)
+ return false;
+
+ m_description = buf;
+ determineModuleVersionFromDescription();
+
+ String mimeDescription = gm();
+ setMIMEDescription(mimeDescription);
+ m_infoIsFromCache = false;
+
+ return true;
+}
+
+void PluginPackage::setMIMEDescription(const String& mimeDescription)
+{
+ m_fullMIMEDescription = mimeDescription.lower();
+
+ Vector<String> types;
+ mimeDescription.lower().split(UChar(';'), false, types);
+ for (unsigned i = 0; i < types.size(); ++i) {
+ Vector<String> mime;
+ types[i].split(UChar(':'), true, mime);
+ if (mime.size() > 0) {
+ Vector<String> exts;
+ if (mime.size() > 1)
+ mime[1].split(UChar(','), false, exts);
+ determineQuirks(mime[0]);
+ m_mimeToExtensions.add(mime[0], exts);
+ if (mime.size() > 2)
+ m_mimeToDescriptions.add(mime[0], mime[2]);
+ }
+ }
+}
+
+static NPError staticPluginQuirkRequiresGtkToolKit_NPN_GetValue(NPP instance, NPNVariable variable, void* value)
+{
+ if (variable == NPNVToolkit) {
+ *static_cast<uint32_t*>(value) = 2;
+ return NPERR_NO_ERROR;
+ }
+
+ return NPN_GetValue(instance, variable, value);
+}
+
+static void initializeGtk(QLibrary* module = 0)
+{
+ // Ensures missing Gtk initialization in some versions of Adobe's flash player
+ // plugin do not cause crashes. See BR# 40567, 44324, and 44405 for details.
+ if (module) {
+ typedef void *(*gtk_init_ptr)(int*, char***);
+ gtk_init_ptr gtkInit = (gtk_init_ptr)module->resolve("gtk_init");
+ if (gtkInit) {
+ // Prevent gtk_init() from replacing the X error handlers, since the Gtk
+ // handlers abort when they receive an X error, thus killing the viewer.
+#ifdef Q_WS_X11
+ int (*old_error_handler)(Display*, XErrorEvent*) = XSetErrorHandler(0);
+ int (*old_io_error_handler)(Display*) = XSetIOErrorHandler(0);
+#endif
+ gtkInit(0, 0);
+#ifdef Q_WS_X11
+ XSetErrorHandler(old_error_handler);
+ XSetIOErrorHandler(old_io_error_handler);
+#endif
+ return;
+ }
+ }
+
+ QLibrary library("libgtk-x11-2.0.so.0");
+ if (library.load()) {
+ typedef void *(*gtk_init_check_ptr)(int*, char***);
+ gtk_init_check_ptr gtkInitCheck = (gtk_init_check_ptr)library.resolve("gtk_init_check");
+ // NOTE: We're using gtk_init_check() since gtk_init() calls exit() on failure.
+ if (gtkInitCheck)
+ (void) gtkInitCheck(0, 0);
+ }
+}
+
+bool PluginPackage::load()
+{
+ if (m_isLoaded) {
+ m_loadCount++;
+ return true;
+ }
+
+ m_module = new QLibrary((QString)m_path);
+ m_module->setLoadHints(QLibrary::ResolveAllSymbolsHint);
+ if (!m_module->load()) {
+ LOG(Plugins, "%s not loaded (%s)", m_path.utf8().data(),
+ m_module->errorString().toLatin1().constData());
+ return false;
+ }
+
+ m_isLoaded = true;
+
+ NP_InitializeFuncPtr NP_Initialize;
+ NPError npErr;
+
+ NP_Initialize = (NP_InitializeFuncPtr)m_module->resolve("NP_Initialize");
+ m_NPP_Shutdown = (NPP_ShutdownProcPtr)m_module->resolve("NP_Shutdown");
+
+ if (!NP_Initialize || !m_NPP_Shutdown)
+ goto abort;
+
+ memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs));
+ m_pluginFuncs.size = sizeof(m_pluginFuncs);
+
+ initializeBrowserFuncs();
+
+ if (m_path.contains("npwrapper.")) {
+ // nspluginwrapper relies on the toolkit value to know if glib is available
+ // It does so in NP_Initialize with a null instance, therefore it is done this way:
+ m_browserFuncs.getvalue = staticPluginQuirkRequiresGtkToolKit_NPN_GetValue;
+ // Workaround Adobe's failure to properly initialize Gtk in some versions
+ // of their flash player plugin.
+ initializeGtk();
+ } else if (m_path.contains("flashplayer")) {
+ // Workaround Adobe's failure to properly initialize Gtk in some versions
+ // of their flash player plugin.
+ initializeGtk(m_module);
+ }
+
+#if defined(XP_UNIX)
+ npErr = NP_Initialize(&m_browserFuncs, &m_pluginFuncs);
+#else
+ npErr = NP_Initialize(&m_browserFuncs);
+#endif
+ if (npErr != NPERR_NO_ERROR)
+ goto abort;
+
+ m_loadCount++;
+ return true;
+
+abort:
+ unloadWithoutShutdown();
+ return false;
+}
+
+uint16_t PluginPackage::NPVersion() const
+{
+ return NP_VERSION_MINOR;
+}
+
+}
diff --git a/Source/WebCore/plugins/qt/PluginViewQt.cpp b/Source/WebCore/plugins/qt/PluginViewQt.cpp
new file mode 100644
index 0000000..fdbe552
--- /dev/null
+++ b/Source/WebCore/plugins/qt/PluginViewQt.cpp
@@ -0,0 +1,1011 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ *
+ * 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"
+
+#if USE(JSC)
+#include "Bridge.h"
+#endif
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "FloatPoint.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"
+#if USE(JSC)
+#include "JSDOMBinding.h"
+#endif
+#include "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformKeyboardEvent.h"
+#include "PluginContainerQt.h"
+#include "PluginDebug.h"
+#include "PluginPackage.h"
+#include "PluginMainThreadScheduler.h"
+#include "QWebPageClient.h"
+#include "RenderLayer.h"
+#include "ScriptController.h"
+#include "Settings.h"
+#include "npruntime_impl.h"
+#include "qwebpage_p.h"
+#include "runtime_root.h"
+
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QGraphicsWidget>
+#include <QKeyEvent>
+#include <QPainter>
+#include <QStyleOptionGraphicsItem>
+#include <QWidget>
+#include <QX11Info>
+#include <X11/X.h>
+#ifndef QT_NO_XRENDER
+#define Bool int
+#define Status int
+#include <X11/extensions/Xrender.h>
+#endif
+#include <runtime/JSLock.h>
+#include <runtime/JSValue.h>
+
+using JSC::ExecState;
+using JSC::Interpreter;
+using JSC::JSLock;
+using JSC::JSObject;
+using JSC::UString;
+
+using std::min;
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#if USE(ACCELERATED_COMPOSITING)
+// Qt's GraphicsLayer (GraphicsLayerQt) requires layers to be QGraphicsWidgets
+class PluginGraphicsLayerQt : public QGraphicsWidget {
+public:
+ PluginGraphicsLayerQt(PluginView* view) : m_view(view) { }
+ ~PluginGraphicsLayerQt() { }
+
+ void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0)
+ {
+ Q_UNUSED(widget);
+ m_view->paintUsingXPixmap(painter, option->exposedRect.toRect());
+ }
+
+private:
+ PluginView* m_view;
+};
+#endif
+
+void PluginView::updatePluginWidget()
+{
+ 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 (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
+ return;
+
+ if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) {
+#if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
+ // On Maemo5, Flash always renders to 16-bit buffer
+ if (m_renderToImage)
+ m_image = QImage(m_windowRect.width(), m_windowRect.height(), QImage::Format_RGB16);
+ else
+#endif
+ {
+ if (m_drawable)
+ XFreePixmap(QX11Info::display(), m_drawable);
+
+ m_drawable = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), m_windowRect.width(), m_windowRect.height(),
+ ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
+ QApplication::syncX(); // make sure that the server knows about the Drawable
+ }
+ }
+
+ // do not call setNPWindowIfNeeded immediately, will be called on paint()
+ m_hasPendingGeometryChange = true;
+
+ // (i) in order to move/resize the plugin window at the same time as the
+ // rest of frame during e.g. scrolling, we set the window geometry
+ // in the paint() function, but as paint() isn't called when the
+ // plugin window is outside the frame which can be caused by a
+ // scroll, we need to move/resize immediately.
+ // (ii) if we are running layout tests from DRT, paint() won't ever get called
+ // so we need to call setNPWindowIfNeeded() if window geometry has changed
+ if (!m_windowRect.intersects(frameView->frameRect())
+ || (QWebPagePrivate::drtRun && platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)))
+ setNPWindowIfNeeded();
+
+ if (!m_platformLayer) {
+ // Make sure we get repainted afterwards. This is necessary for downward
+ // scrolling to move the plugin widget properly.
+ invalidate();
+ }
+}
+
+void PluginView::setFocus(bool focused)
+{
+ if (platformPluginWidget()) {
+ if (focused)
+ platformPluginWidget()->setFocus(Qt::OtherFocusReason);
+ } else {
+ Widget::setFocus(focused);
+ }
+}
+
+void PluginView::show()
+{
+ Q_ASSERT(platformPluginWidget() == platformWidget());
+ Widget::show();
+}
+
+void PluginView::hide()
+{
+ Q_ASSERT(platformPluginWidget() == platformWidget());
+ Widget::hide();
+}
+
+#if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
+void PluginView::paintUsingImageSurfaceExtension(QPainter* painter, const IntRect& exposedRect)
+{
+ NPImageExpose imageExpose;
+ QPoint offset;
+ QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
+ const bool surfaceHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent());
+
+ QPaintDevice* surface = QPainter::redirected(painter->device(), &offset);
+
+ // If the surface is a QImage, we can render directly into it
+ if (surfaceHasUntransformedContents && surface && surface->devType() == QInternal::Image) {
+ QImage* image = static_cast<QImage*>(surface);
+ offset = -offset; // negating the offset gives us the offset of the view within the surface
+ imageExpose.data = reinterpret_cast<char*>(image->bits());
+ imageExpose.dataSize.width = image->width();
+ imageExpose.dataSize.height = image->height();
+ imageExpose.stride = image->bytesPerLine();
+ imageExpose.depth = image->depth(); // this is guaranteed to be 16 on Maemo5
+ imageExpose.translateX = offset.x() + m_windowRect.x();
+ imageExpose.translateY = offset.y() + m_windowRect.y();
+ imageExpose.scaleX = 1;
+ imageExpose.scaleY = 1;
+ } else {
+ if (m_isTransparent) {
+ // On Maemo5, Flash expects the buffer to contain the contents that are below it.
+ // We don't support transparency for non-raster graphicssystem, so clean the image
+ // before giving to Flash.
+ QPainter imagePainter(&m_image);
+ imagePainter.fillRect(exposedRect, Qt::white);
+ }
+
+ imageExpose.data = reinterpret_cast<char*>(m_image.bits());
+ imageExpose.dataSize.width = m_image.width();
+ imageExpose.dataSize.height = m_image.height();
+ imageExpose.stride = m_image.bytesPerLine();
+ imageExpose.depth = m_image.depth();
+ imageExpose.translateX = 0;
+ imageExpose.translateY = 0;
+ imageExpose.scaleX = 1;
+ imageExpose.scaleY = 1;
+ }
+ imageExpose.x = exposedRect.x();
+ imageExpose.y = exposedRect.y();
+ imageExpose.width = exposedRect.width();
+ imageExpose.height = exposedRect.height();
+
+ XEvent xevent;
+ memset(&xevent, 0, sizeof(XEvent));
+ XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
+ exposeEvent.type = GraphicsExpose;
+ exposeEvent.display = 0;
+ exposeEvent.drawable = reinterpret_cast<XID>(&imageExpose);
+ exposeEvent.x = exposedRect.x();
+ exposeEvent.y = exposedRect.y();
+ exposeEvent.width = exposedRect.width();
+ exposeEvent.height = exposedRect.height();
+
+ dispatchNPEvent(xevent);
+
+ if (!surfaceHasUntransformedContents || !surface || surface->devType() != QInternal::Image)
+ painter->drawImage(QPoint(frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y()), m_image, exposedRect);
+}
+#endif
+
+void PluginView::paintUsingXPixmap(QPainter* painter, const QRect &exposedRect)
+{
+ QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared);
+ const int drawableDepth = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth;
+ ASSERT(drawableDepth == qtDrawable.depth());
+ const bool syncX = m_pluginDisplay && m_pluginDisplay != QX11Info::display();
+
+ // When printing, Qt uses a QPicture to capture the output in preview mode. The
+ // QPicture holds a reference to the X Pixmap. As a result, the print preview would
+ // update itself when the X Pixmap changes. To prevent this, we create a copy.
+ if (m_element->document()->printing())
+ qtDrawable = qtDrawable.copy();
+
+ if (m_isTransparent && drawableDepth != 32) {
+ // Attempt content propagation for drawable with no alpha by copying over from the backing store
+ QPoint offset;
+ QPaintDevice* backingStoreDevice = QPainter::redirected(painter->device(), &offset);
+ offset = -offset; // negating the offset gives us the offset of the view within the backing store pixmap
+
+ const bool hasValidBackingStore = backingStoreDevice && backingStoreDevice->devType() == QInternal::Pixmap;
+ QPixmap* backingStorePixmap = static_cast<QPixmap*>(backingStoreDevice);
+
+ // We cannot grab contents from the backing store when painting on QGraphicsView items
+ // (because backing store contents are already transformed). What we really mean to do
+ // here is to check if we are painting on QWebView, but let's be a little permissive :)
+ QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
+ const bool backingStoreHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent());
+
+ if (hasValidBackingStore && backingStorePixmap->depth() == drawableDepth
+ && backingStoreHasUntransformedContents) {
+ GC gc = XDefaultGC(QX11Info::display(), QX11Info::appScreen());
+ XCopyArea(QX11Info::display(), backingStorePixmap->handle(), m_drawable, gc,
+ offset.x() + m_windowRect.x() + exposedRect.x(), offset.y() + m_windowRect.y() + exposedRect.y(),
+ exposedRect.width(), exposedRect.height(), exposedRect.x(), exposedRect.y());
+ } else { // no backing store, clean the pixmap because the plugin thinks its transparent
+ QPainter painter(&qtDrawable);
+ painter.fillRect(exposedRect, Qt::white);
+ }
+
+ if (syncX)
+ QApplication::syncX();
+ }
+
+ XEvent xevent;
+ memset(&xevent, 0, sizeof(XEvent));
+ XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
+ exposeEvent.type = GraphicsExpose;
+ exposeEvent.display = QX11Info::display();
+ exposeEvent.drawable = qtDrawable.handle();
+ exposeEvent.x = exposedRect.x();
+ exposeEvent.y = exposedRect.y();
+ exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
+ exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
+
+ dispatchNPEvent(xevent);
+
+ if (syncX)
+ XSync(m_pluginDisplay, false); // sync changes by plugin
+
+ painter->drawPixmap(QPoint(exposedRect.x(), exposedRect.y()), qtDrawable, exposedRect);
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_isStarted) {
+ paintMissingPluginIcon(context, rect);
+ return;
+ }
+
+ if (context->paintingDisabled())
+ return;
+
+ setNPWindowIfNeeded();
+
+ if (m_isWindowed)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_platformLayer)
+ return;
+#endif
+
+ if (!m_drawable
+#if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
+ && m_image.isNull()
+#endif
+ )
+ return;
+
+ QPainter* painter = context->platformContext();
+ IntRect exposedRect(rect);
+ exposedRect.intersect(frameRect());
+ exposedRect.move(-frameRect().x(), -frameRect().y());
+
+#if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
+ if (!m_image.isNull()) {
+ paintUsingImageSurfaceExtension(painter, exposedRect);
+ return;
+ }
+#endif
+
+ painter->translate(frameRect().x(), frameRect().y());
+ paintUsingXPixmap(painter, exposedRect);
+ painter->translate(-frameRect().x(), -frameRect().y());
+}
+
+// TODO: Unify across ports.
+bool PluginView::dispatchNPEvent(NPEvent& event)
+{
+ if (!m_plugin->pluginFuncs()->event)
+ return false;
+
+ PluginView::setCurrentPluginView(this);
+#if USE(JSC)
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+#endif
+ setCallingPlugin(true);
+ bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+
+ return accepted;
+}
+
+void setSharedXEventFields(XEvent* xEvent, QWidget* ownerWidget)
+{
+ xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
+ xEvent->xany.send_event = false;
+ xEvent->xany.display = QX11Info::display();
+ // NOTE: event->xany.window doesn't always respond to the .window property of other XEvent's
+ // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify
+ // events; thus, this is right:
+ xEvent->xany.window = ownerWidget ? ownerWidget->window()->handle() : 0;
+}
+
+void PluginView::initXEvent(XEvent* xEvent)
+{
+ memset(xEvent, 0, sizeof(XEvent));
+
+ QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
+ QWidget* ownerWidget = client ? client->ownerWidget() : 0;
+ setSharedXEventFields(xEvent, ownerWidget);
+}
+
+void setXKeyEventSpecificFields(XEvent* xEvent, KeyboardEvent* event)
+{
+ const PlatformKeyboardEvent* keyEvent = event->keyEvent();
+
+ xEvent->type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // ints as Qt unsets KeyPress and KeyRelease
+ xEvent->xkey.root = QX11Info::appRootWindow();
+ xEvent->xkey.subwindow = 0; // we have no child window
+ xEvent->xkey.time = event->timeStamp();
+ xEvent->xkey.state = keyEvent->nativeModifiers();
+ xEvent->xkey.keycode = keyEvent->nativeScanCode();
+
+ // We may not have a nativeScanCode() if the key event is from DRT's eventsender. In that
+ // case just populate the XEvent's keycode with the Qt platform-independent keycode. The only
+ // place this keycode will be used is in webkit_test_plugin_handle_event().
+ if (QWebPagePrivate::drtRun && !xEvent->xkey.keycode) {
+ QKeyEvent* qKeyEvent = keyEvent->qtEvent();
+ ASSERT(qKeyEvent);
+ if (!qKeyEvent->text().isEmpty())
+ xEvent->xkey.keycode = int(qKeyEvent->text().at(0).unicode() + qKeyEvent->modifiers());
+ else if (qKeyEvent->key() && (qKeyEvent->key() != Qt::Key_unknown))
+ xEvent->xkey.keycode = int(qKeyEvent->key() + qKeyEvent->modifiers());
+ }
+
+ xEvent->xkey.same_screen = true;
+
+ // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
+ // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
+ // set to their normal Xserver values. e.g. Key events don't have a position.
+ // source: https://developer.mozilla.org/en/NPEvent
+ xEvent->xkey.x = 0;
+ xEvent->xkey.y = 0;
+ xEvent->xkey.x_root = 0;
+ xEvent->xkey.y_root = 0;
+}
+
+void PluginView::handleKeyboardEvent(KeyboardEvent* event)
+{
+ if (m_isWindowed)
+ return;
+
+ if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
+ return;
+
+ XEvent npEvent;
+ initXEvent(&npEvent);
+ setXKeyEventSpecificFields(&npEvent, event);
+
+ if (!dispatchNPEvent(npEvent))
+ event->setDefaultHandled();
+}
+
+static unsigned int inputEventState(MouseEvent* event)
+{
+ unsigned int state = 0;
+ if (event->ctrlKey())
+ state |= ControlMask;
+ if (event->shiftKey())
+ state |= ShiftMask;
+ if (event->altKey())
+ state |= Mod1Mask;
+ if (event->metaKey())
+ state |= Mod4Mask;
+ return state;
+}
+
+static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
+{
+ XButtonEvent& xbutton = xEvent->xbutton;
+ xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
+ xbutton.root = QX11Info::appRootWindow();
+ xbutton.subwindow = 0;
+ xbutton.time = event->timeStamp();
+ xbutton.x = postZoomPos.x();
+ xbutton.y = postZoomPos.y();
+ xbutton.x_root = event->screenX();
+ xbutton.y_root = event->screenY();
+ xbutton.state = inputEventState(event);
+ switch (event->button()) {
+ case MiddleButton:
+ xbutton.button = Button2;
+ break;
+ case RightButton:
+ xbutton.button = Button3;
+ break;
+ case LeftButton:
+ default:
+ xbutton.button = Button1;
+ break;
+ }
+ xbutton.same_screen = true;
+}
+
+static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
+{
+ XMotionEvent& xmotion = xEvent->xmotion;
+ xmotion.type = MotionNotify;
+ xmotion.root = QX11Info::appRootWindow();
+ xmotion.subwindow = 0;
+ xmotion.time = event->timeStamp();
+ xmotion.x = postZoomPos.x();
+ xmotion.y = postZoomPos.y();
+ xmotion.x_root = event->screenX();
+ xmotion.y_root = event->screenY();
+ xmotion.state = inputEventState(event);
+ xmotion.is_hint = NotifyNormal;
+ xmotion.same_screen = true;
+}
+
+static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos)
+{
+ XCrossingEvent& xcrossing = xEvent->xcrossing;
+ xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
+ xcrossing.root = QX11Info::appRootWindow();
+ xcrossing.subwindow = 0;
+ xcrossing.time = event->timeStamp();
+ xcrossing.x = postZoomPos.y();
+ xcrossing.y = postZoomPos.x();
+ xcrossing.x_root = event->screenX();
+ xcrossing.y_root = event->screenY();
+ xcrossing.state = inputEventState(event);
+ xcrossing.mode = NotifyNormal;
+ xcrossing.detail = NotifyDetailNone;
+ xcrossing.same_screen = true;
+ xcrossing.focus = false;
+}
+
+void PluginView::handleMouseEvent(MouseEvent* event)
+{
+ if (m_isWindowed)
+ return;
+
+ if (event->button() == RightButton && m_plugin->quirks().contains(PluginQuirkIgnoreRightClickInWindowlessMode))
+ return;
+
+ if (event->type() == eventNames().mousedownEvent) {
+ // Give focus to the plugin on click
+ if (Page* page = m_parentFrame->page())
+ page->focusController()->setActive(true);
+
+ focusPluginElement();
+ }
+
+ XEvent npEvent;
+ initXEvent(&npEvent);
+
+ IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
+
+ if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
+ setXButtonEventSpecificFields(&npEvent, event, postZoomPos);
+ else if (event->type() == eventNames().mousemoveEvent)
+ setXMotionEventSpecificFields(&npEvent, event, postZoomPos);
+ else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent)
+ setXCrossingEventSpecificFields(&npEvent, event, postZoomPos);
+ else
+ return;
+
+ if (!dispatchNPEvent(npEvent))
+ event->setDefaultHandled();
+}
+
+void PluginView::handleFocusInEvent()
+{
+ XEvent npEvent;
+ initXEvent(&npEvent);
+
+ XFocusChangeEvent& event = npEvent.xfocus;
+ event.type = 9; /* int as Qt unsets FocusIn */
+ event.mode = NotifyNormal;
+ event.detail = NotifyDetailNone;
+
+ dispatchNPEvent(npEvent);
+}
+
+void PluginView::handleFocusOutEvent()
+{
+ XEvent npEvent;
+ initXEvent(&npEvent);
+
+ XFocusChangeEvent& event = npEvent.xfocus;
+ event.type = 10; /* int as Qt unsets FocusOut */
+ event.mode = NotifyNormal;
+ event.detail = NotifyDetailNone;
+
+ dispatchNPEvent(npEvent);
+}
+
+void PluginView::setParent(ScrollView* parent)
+{
+ Widget::setParent(parent);
+
+ if (parent)
+ init();
+}
+
+void PluginView::setNPWindowRect(const IntRect&)
+{
+ if (!m_isWindowed)
+ setNPWindowIfNeeded();
+}
+
+void PluginView::setNPWindowIfNeeded()
+{
+ if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
+ return;
+
+ // If the plugin didn't load sucessfully, no point in calling setwindow
+ if (m_status != PluginStatusLoadedSuccessfully)
+ return;
+
+ // On Unix, only call plugin if it's full-page or windowed
+ if (m_mode != NP_FULL && m_mode != NP_EMBED)
+ return;
+
+ // Check if the platformPluginWidget still exists
+ if (m_isWindowed && !platformPluginWidget())
+ return;
+
+ if (!m_hasPendingGeometryChange)
+ return;
+ m_hasPendingGeometryChange = false;
+
+ if (m_isWindowed) {
+ platformPluginWidget()->setGeometry(m_windowRect);
+ // if setMask is set with an empty QRegion, no clipping will
+ // be performed, so in that case we hide the plugin view
+ platformPluginWidget()->setVisible(!m_clipRect.isEmpty());
+ platformPluginWidget()->setMask(QRegion(m_clipRect));
+
+ m_npWindow.x = m_windowRect.x();
+ m_npWindow.y = m_windowRect.y();
+ } else {
+ m_npWindow.x = 0;
+ m_npWindow.y = 0;
+ }
+
+ // If the width or height are null, set the clipRect to null, indicating that
+ // the plugin is not visible/scrolled out.
+ if (!m_clipRect.width() || !m_clipRect.height()) {
+ m_npWindow.clipRect.left = 0;
+ m_npWindow.clipRect.right = 0;
+ m_npWindow.clipRect.top = 0;
+ m_npWindow.clipRect.bottom = 0;
+ } else {
+ // Clipping rectangle of the plug-in; the origin is the top left corner of the drawable or window.
+ m_npWindow.clipRect.left = m_npWindow.x + m_clipRect.x();
+ m_npWindow.clipRect.top = m_npWindow.y + m_clipRect.y();
+ m_npWindow.clipRect.right = m_npWindow.x + m_clipRect.x() + m_clipRect.width();
+ m_npWindow.clipRect.bottom = m_npWindow.y + m_clipRect.y() + m_clipRect.height();
+ }
+
+ if (m_plugin->quirks().contains(PluginQuirkDontCallSetWindowMoreThanOnce)) {
+ // FLASH WORKAROUND: Only set initially. Multiple calls to
+ // setNPWindow() cause the plugin to crash in windowed mode.
+ if (!m_isWindowed || m_npWindow.width == -1 || m_npWindow.height == -1) {
+ m_npWindow.width = m_windowRect.width();
+ m_npWindow.height = m_windowRect.height();
+ }
+ } else {
+ m_npWindow.width = m_windowRect.width();
+ m_npWindow.height = m_windowRect.height();
+ }
+
+ PluginView::setCurrentPluginView(this);
+#if USE(JSC)
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+#endif
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+}
+
+void PluginView::setParentVisible(bool visible)
+{
+ if (isParentVisible() == visible)
+ return;
+
+ Widget::setParentVisible(visible);
+
+ if (isSelfVisible() && platformPluginWidget())
+ platformPluginWidget()->setVisible(visible);
+}
+
+NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
+{
+ String filename(buf, len);
+
+ if (filename.startsWith("file:///"))
+ filename = filename.substring(8);
+
+ long long size;
+ if (!getFileSize(filename, size))
+ return NPERR_FILE_NOT_FOUND;
+
+ FILE* fileHandle = fopen((filename.utf8()).data(), "r");
+ if (!fileHandle)
+ return NPERR_FILE_NOT_FOUND;
+
+ buffer.resize(size);
+ int bytesRead = fread(buffer.data(), 1, size, fileHandle);
+
+ fclose(fileHandle);
+
+ if (bytesRead <= 0)
+ return NPERR_FILE_NOT_FOUND;
+
+ return NPERR_NO_ERROR;
+}
+
+bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
+{
+ switch (variable) {
+ case NPNVToolkit:
+ *static_cast<uint32_t*>(value) = 0;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVSupportsXEmbedBool:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVjavascriptEnabledBool:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVSupportsWindowless:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+#if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
+ case NPNVSupportsWindowlessLocal:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+#endif
+
+ default:
+ return false;
+ }
+}
+
+bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
+{
+ switch (variable) {
+ case NPNVxDisplay:
+ *(void **)value = QX11Info::display();
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVxtAppContext:
+ *result = NPERR_GENERIC_ERROR;
+ return true;
+
+ case NPNVnetscapeWindow: {
+ void* w = reinterpret_cast<void*>(value);
+ QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
+ *((XID *)w) = client ? client->ownerWidget()->window()->winId() : 0;
+ *result = NPERR_NO_ERROR;
+ return true;
+ }
+
+ case NPNVToolkit:
+ if (m_plugin->quirks().contains(PluginQuirkRequiresGtkToolKit)) {
+ *((uint32_t *)value) = 2;
+ *result = NPERR_NO_ERROR;
+ return true;
+ }
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+void PluginView::invalidateRect(const IntRect& rect)
+{
+#if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
+ if (m_platformLayer) {
+ m_platformLayer->update(QRectF(rect));
+ return;
+ }
+#endif
+
+ if (m_isWindowed) {
+ if (platformWidget())
+ platformWidget()->update(rect);
+ 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);
+ invalidateRect(r);
+}
+
+void PluginView::invalidateRegion(NPRegion region)
+{
+ Q_UNUSED(region);
+ invalidate();
+}
+
+void PluginView::forceRedraw()
+{
+ invalidate();
+}
+
+static Display *getPluginDisplay()
+{
+ // The plugin toolkit might run using a different X connection. At the moment, we only
+ // support gdk based plugins (like flash) that use a different X connection.
+ // The code below has the same effect as this one:
+ // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
+ QLibrary library("libgdk-x11-2.0", 0);
+ if (!library.load())
+ return 0;
+
+ typedef void *(*gdk_display_get_default_ptr)();
+ gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default");
+ if (!gdk_display_get_default)
+ return 0;
+
+ typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *);
+ gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay");
+ if (!gdk_x11_display_get_xdisplay)
+ return 0;
+
+ return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default());
+}
+
+static void getVisualAndColormap(int depth, Visual **visual, Colormap *colormap)
+{
+ *visual = 0;
+ *colormap = 0;
+
+#ifndef QT_NO_XRENDER
+ static const bool useXRender = qgetenv("QT_X11_NO_XRENDER").isNull(); // Should also check for XRender >= 0.5
+#else
+ static const bool useXRender = false;
+#endif
+
+ if (!useXRender && depth == 32)
+ return;
+
+ int nvi;
+ XVisualInfo templ;
+ templ.screen = QX11Info::appScreen();
+ templ.depth = depth;
+ templ.c_class = TrueColor;
+ XVisualInfo* xvi = XGetVisualInfo(QX11Info::display(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi);
+
+ if (!xvi)
+ return;
+
+#ifndef QT_NO_XRENDER
+ if (depth == 32) {
+ for (int idx = 0; idx < nvi; ++idx) {
+ XRenderPictFormat* format = XRenderFindVisualFormat(QX11Info::display(), xvi[idx].visual);
+ if (format->type == PictTypeDirect && format->direct.alphaMask) {
+ *visual = xvi[idx].visual;
+ break;
+ }
+ }
+ } else
+#endif // QT_NO_XRENDER
+ *visual = xvi[0].visual;
+
+ XFree(xvi);
+
+ if (*visual)
+ *colormap = XCreateColormap(QX11Info::display(), QX11Info::appRootWindow(), *visual, AllocNone);
+}
+
+bool PluginView::platformStart()
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_status == PluginStatusLoadedSuccessfully);
+
+ if (m_plugin->pluginFuncs()->getvalue) {
+ PluginView::setCurrentPluginView(this);
+#if USE(JSC)
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+#endif
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ }
+
+ if (m_isWindowed) {
+ QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
+ if (m_needsXEmbed && client) {
+ setPlatformWidget(new PluginContainerQt(this, client->ownerWidget()));
+ // sync our XEmbed container window creation before sending the xid to plugins.
+ QApplication::syncX();
+ } else {
+ notImplemented();
+ m_status = PluginStatusCanNotLoadPlugin;
+ return false;
+ }
+ } else {
+ setPlatformWidget(0);
+ m_pluginDisplay = getPluginDisplay();
+
+#if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
+ if (m_parentFrame->page()->chrome()->client()->allowsAcceleratedCompositing()
+ && m_parentFrame->page()->settings()
+ && m_parentFrame->page()->settings()->acceleratedCompositingEnabled()) {
+ m_platformLayer = new PluginGraphicsLayerQt(this);
+ // Trigger layer computation in RenderLayerCompositor
+ m_element->setNeedsStyleRecalc(SyntheticStyleChange);
+ }
+#endif
+ }
+
+ show();
+
+ NPSetWindowCallbackStruct* wsi = new NPSetWindowCallbackStruct();
+ wsi->type = 0;
+
+ if (m_isWindowed) {
+ const QX11Info* x11Info = &platformPluginWidget()->x11Info();
+
+ wsi->display = x11Info->display();
+ wsi->visual = (Visual*)x11Info->visual();
+ wsi->depth = x11Info->depth();
+ wsi->colormap = x11Info->colormap();
+
+ m_npWindow.type = NPWindowTypeWindow;
+ m_npWindow.window = (void*)platformPluginWidget()->winId();
+ m_npWindow.width = -1;
+ m_npWindow.height = -1;
+ } else {
+ const QX11Info* x11Info = &QApplication::desktop()->x11Info();
+
+ if (x11Info->depth() == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) {
+ getVisualAndColormap(32, &m_visual, &m_colormap);
+ wsi->depth = 32;
+ }
+
+ if (!m_visual) {
+ getVisualAndColormap(x11Info->depth(), &m_visual, &m_colormap);
+ wsi->depth = x11Info->depth();
+ }
+
+ wsi->display = x11Info->display();
+ wsi->visual = m_visual;
+ wsi->colormap = m_colormap;
+
+ m_npWindow.type = NPWindowTypeDrawable;
+ m_npWindow.window = 0; // Not used?
+ m_npWindow.x = 0;
+ m_npWindow.y = 0;
+ m_npWindow.width = -1;
+ m_npWindow.height = -1;
+ }
+
+ m_npWindow.ws_info = wsi;
+
+ if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) {
+ updatePluginWidget();
+ setNPWindowIfNeeded();
+ }
+
+ return true;
+}
+
+void PluginView::platformDestroy()
+{
+ if (platformPluginWidget())
+ delete platformPluginWidget();
+
+ if (m_drawable)
+ XFreePixmap(QX11Info::display(), m_drawable);
+
+ if (m_colormap)
+ XFreeColormap(QX11Info::display(), m_colormap);
+}
+
+void PluginView::halt()
+{
+}
+
+void PluginView::restart()
+{
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* PluginView::platformLayer() const
+{
+ return m_platformLayer.get();
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/symbian/PluginContainerSymbian.cpp b/Source/WebCore/plugins/symbian/PluginContainerSymbian.cpp
new file mode 100644
index 0000000..b839870
--- /dev/null
+++ b/Source/WebCore/plugins/symbian/PluginContainerSymbian.cpp
@@ -0,0 +1,77 @@
+/*
+ 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.
+*/
+
+#include "config.h"
+#include "PluginContainerSymbian.h"
+
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PluginView.h"
+
+#include <QApplication>
+#include <QWidget>
+
+using namespace WebCore;
+
+PluginContainerSymbian::PluginContainerSymbian(PluginView* view, QWidget* parent, QGraphicsProxyWidget* proxy)
+ : QWidget(parent)
+ , m_pluginView(view)
+ , m_proxy(proxy)
+ , m_hasPendingGeometryChange(false)
+{
+}
+
+PluginContainerSymbian::~PluginContainerSymbian()
+{
+}
+
+void PluginContainerSymbian::requestGeometry(const QRect& rect, const QRegion& clip)
+{
+ if (m_windowRect != rect || m_clipRegion != clip) {
+ m_windowRect = rect;
+ m_clipRegion = clip;
+ m_hasPendingGeometryChange = true;
+ }
+}
+
+void PluginContainerSymbian::adjustGeometry()
+{
+ if (m_hasPendingGeometryChange) {
+ setGeometry(m_windowRect);
+ setMask(m_clipRegion);
+ m_hasPendingGeometryChange = false;
+ }
+}
+
+void PluginContainerSymbian::focusInEvent(QFocusEvent*)
+{
+ if (Page* page = m_pluginView->parentFrame()->page())
+ page->focusController()->setActive(true);
+
+ m_pluginView->focusPluginElement();
+}
+
+void PluginContainerSymbian::focusOutEvent(QFocusEvent*)
+{
+ if (Page* page = m_pluginView->parentFrame()->page())
+ page->focusController()->setActive(false);
+}
diff --git a/Source/WebCore/plugins/symbian/PluginContainerSymbian.h b/Source/WebCore/plugins/symbian/PluginContainerSymbian.h
new file mode 100644
index 0000000..fead872
--- /dev/null
+++ b/Source/WebCore/plugins/symbian/PluginContainerSymbian.h
@@ -0,0 +1,53 @@
+/*
+ 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.
+*/
+
+#ifndef PluginContainerSymbian_h
+#define PluginContainerSymbian_h
+
+#include <QWidget>
+
+class QGraphicsProxyWidget;
+
+namespace WebCore {
+
+ class PluginView;
+
+ class PluginContainerSymbian : public QWidget {
+ Q_OBJECT
+ public:
+ PluginContainerSymbian(PluginView*, QWidget* parent, QGraphicsProxyWidget* proxy = 0);
+ ~PluginContainerSymbian();
+
+ void requestGeometry(const QRect&, const QRegion& clip = QRegion());
+ void adjustGeometry();
+ QGraphicsProxyWidget* proxy() { return m_proxy; }
+
+ protected:
+ virtual void focusInEvent(QFocusEvent*);
+ virtual void focusOutEvent(QFocusEvent*);
+ private:
+ PluginView* m_pluginView;
+ QGraphicsProxyWidget* m_proxy;
+ QRect m_windowRect;
+ QRegion m_clipRegion;
+ bool m_hasPendingGeometryChange;
+ };
+}
+
+#endif // PluginContainerSymbian_h
diff --git a/Source/WebCore/plugins/symbian/PluginDatabaseSymbian.cpp b/Source/WebCore/plugins/symbian/PluginDatabaseSymbian.cpp
new file mode 100644
index 0000000..2e09296
--- /dev/null
+++ b/Source/WebCore/plugins/symbian/PluginDatabaseSymbian.cpp
@@ -0,0 +1,79 @@
+/*
+ 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.
+*/
+#include "config.h"
+#include "PluginDatabase.h"
+
+#include <QFileInfo>
+#include <f32file.h>
+
+static const char QTPLUGIN_FILTER[] = "*.qtplugin";
+static const char QT_PLUGIN_FOLDER[] = ":\\resource\\qt\\plugins\\npqtplugins\\";
+
+namespace WebCore {
+
+Vector<String> PluginDatabase::defaultPluginDirectories()
+{
+ Vector<String> directories;
+ //find the installation drive
+ TDriveList drivelist;
+ TChar driveLetter;
+ RFs fsSession;
+
+ if (fsSession.Connect() == KErrNone && fsSession.DriveList(drivelist) == KErrNone) {
+ for (TInt driveNumber = EDriveA; driveNumber <= EDriveZ; driveNumber++) {
+ if (drivelist[driveNumber] && fsSession.DriveToChar(driveNumber, driveLetter) == KErrNone) {
+ QString driveStringValue(QChar((uint)driveLetter.GetUpperCase()));
+ QString stubDirPath;
+ stubDirPath.append(driveStringValue);
+ stubDirPath.append(QT_PLUGIN_FOLDER);
+ if (QFileInfo(stubDirPath).exists())
+ directories.append(stubDirPath);
+ }
+ }
+ }
+
+ fsSession.Close();
+ return directories;
+}
+
+bool PluginDatabase::isPreferredPluginDirectory(const String& path)
+{
+ return true;
+}
+
+void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const
+{
+ // FIXME: This should be a case insensitive set.
+ HashSet<String> uniqueFilenames;
+
+ String fileNameFilter(QTPLUGIN_FILTER);
+
+ Vector<String>::const_iterator dirsEnd = m_pluginDirectories.end();
+ for (Vector<String>::const_iterator dIt = m_pluginDirectories.begin(); dIt != dirsEnd; ++dIt) {
+ Vector<String> pluginPaths = listDirectory(*dIt, fileNameFilter);
+ Vector<String>::const_iterator pluginsEnd = pluginPaths.end();
+ for (Vector<String>::const_iterator pIt = pluginPaths.begin(); pIt != pluginsEnd; ++pIt) {
+ if (!fileExists(*pIt))
+ continue;
+ paths.add(*pIt);
+ }
+ }
+}
+
+}
diff --git a/Source/WebCore/plugins/symbian/PluginPackageSymbian.cpp b/Source/WebCore/plugins/symbian/PluginPackageSymbian.cpp
new file mode 100644
index 0000000..7fca625
--- /dev/null
+++ b/Source/WebCore/plugins/symbian/PluginPackageSymbian.cpp
@@ -0,0 +1,182 @@
+/*
+ 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.
+*/
+#include "config.h"
+#include "PluginPackage.h"
+
+#include "MIMETypeRegistry.h"
+#include "npinterface.h"
+#include "npruntime_impl.h"
+#include "PluginDatabase.h"
+#include "PluginDebug.h"
+#include <QPluginLoader>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+bool PluginPackage::fetchInfo()
+{
+ if (!load())
+ return false;
+
+ char* buf = 0;
+ NPError err = m_pluginFuncs.getvalue(0, NPPVpluginNameString, (void *)&buf);
+ m_name = buf;
+ err = m_pluginFuncs.getvalue(0, NPPVpluginDescriptionString, (void *)&buf);
+ m_description = buf;
+
+ determineModuleVersionFromDescription();
+
+ String s = m_npInterface->NP_GetMIMEDescription();
+ Vector<String> types;
+ s.split(UChar('|'), false, types); // <MIME1>;<ext1,ext2,ext3,...>;<Description>|<MIME2>|<MIME3>|...
+
+ for (int i = 0; i < types.size(); ++i) {
+ Vector<String> mime;
+ types[i].split(UChar(';'), true, mime); // <MIME1>;<ext1,ext2,ext3,...>;<Description>
+ if (mime.size() > 0) {
+ Vector<String> exts;
+ if (mime.size() > 1)
+ mime[1].split(UChar(','), false, exts); // <ext1,ext2,ext3,...>
+
+ m_mimeToExtensions.add(mime[0], exts); // <MIME>,<ext1,ext2,ext3>
+ if (mime.size() > 2)
+ m_mimeToDescriptions.add(mime[0], mime[2]); // <MIME>,<Description>
+ }
+ }
+ unload();
+ return true;
+}
+
+bool PluginPackage::load()
+{
+ if (m_isLoaded) {
+ m_loadCount++;
+ return true;
+ }
+
+ m_pluginLoader = new QPluginLoader(m_path);
+ if (!m_pluginLoader->load()) {
+ delete m_pluginLoader;
+ m_pluginLoader = 0;
+ return false;
+ }
+
+ QObject* plugin = m_pluginLoader->instance();
+ if (!plugin) {
+ m_pluginLoader->unload();
+ delete m_pluginLoader;
+ m_pluginLoader = 0;
+ return false;
+ }
+
+ // Plugin instance created
+ // Cast plugin to NPInterface,
+ m_npInterface = qobject_cast<NPInterface*>(plugin);
+ if (!m_npInterface) {
+ m_pluginLoader->unload();
+ delete m_pluginLoader;
+ m_pluginLoader = 0;
+ return false;
+ }
+
+ m_isLoaded = true;
+
+ NPError npErr;
+ memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs));
+ m_pluginFuncs.size = sizeof(m_pluginFuncs);
+ 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.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.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_HasMethod;
+ m_browserFuncs.hasmethod = _NPN_HasProperty;
+ m_browserFuncs.setexception = _NPN_SetException;
+ m_browserFuncs.enumerate = _NPN_Enumerate;
+ m_browserFuncs.construct = _NPN_Construct;
+
+ npErr = m_npInterface->NP_Initialize(&m_browserFuncs, &m_pluginFuncs);
+ if (npErr != NPERR_NO_ERROR) {
+ m_pluginLoader->unload();
+ delete m_pluginLoader;
+ m_pluginLoader = 0;
+ return false;
+ }
+
+ m_loadCount++;
+ return true;
+}
+
+void PluginPackage::unload()
+{
+ if (!m_isLoaded)
+ return;
+
+ if (--m_loadCount > 0)
+ return;
+
+ m_isLoaded = false;
+ m_npInterface->NP_Shutdown();
+
+ m_pluginLoader->unload();
+ delete m_pluginLoader;
+ m_pluginLoader = 0;
+}
+
+uint16_t PluginPackage::NPVersion() const
+{
+ return NP_VERSION_MINOR;
+}
+}
+
diff --git a/Source/WebCore/plugins/symbian/PluginViewSymbian.cpp b/Source/WebCore/plugins/symbian/PluginViewSymbian.cpp
new file mode 100644
index 0000000..b8a72b1
--- /dev/null
+++ b/Source/WebCore/plugins/symbian/PluginViewSymbian.cpp
@@ -0,0 +1,441 @@
+/*
+ Copyright (C) 2009, 2010 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.
+*/
+#include "config.h"
+#include "PluginView.h"
+
+#include "Bridge.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.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 "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PluginContainerSymbian.h"
+#include "PluginDebug.h"
+#include "PluginMainThreadScheduler.h"
+#include "PluginPackage.h"
+#include "QWebPageClient.h"
+#include "RenderLayer.h"
+#include "ScriptController.h"
+#include "Settings.h"
+#include "npfunctions.h"
+#include "npinterface.h"
+#include "npruntime_impl.h"
+#include "qgraphicswebview.h"
+#include "runtime_root.h"
+#include <QGraphicsProxyWidget>
+#include <QKeyEvent>
+#include <QPixmap>
+#include <QRegion>
+#include <QVector>
+#include <QWidget>
+#include <runtime/JSLock.h>
+#include <runtime/JSValue.h>
+
+using JSC::ExecState;
+using JSC::Interpreter;
+using JSC::JSLock;
+using JSC::JSObject;
+using JSC::UString;
+
+using namespace std;
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+void PluginView::updatePluginWidget()
+{
+ 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 (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
+ return;
+
+ // in order to move/resize the plugin window at the same time as the rest of frame
+ // during e.g. scrolling, we set the mask and geometry in the paint() function, but
+ // as paint() isn't called when the plugin window is outside the frame which can
+ // be caused by a scroll, we need to move/resize immediately.
+ if (!m_windowRect.intersects(frameView->frameRect()))
+ setNPWindowIfNeeded();
+}
+
+void PluginView::setFocus(bool focused)
+{
+ if (platformPluginWidget()) {
+ if (focused)
+ platformPluginWidget()->setFocus(Qt::OtherFocusReason);
+ } else {
+ Widget::setFocus(focused);
+ }
+}
+
+void PluginView::show()
+{
+ setSelfVisible(true);
+
+ if (isParentVisible() && platformPluginWidget())
+ platformPluginWidget()->setVisible(true);
+}
+
+void PluginView::hide()
+{
+ setSelfVisible(false);
+
+ if (isParentVisible() && platformPluginWidget())
+ platformPluginWidget()->setVisible(false);
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_isStarted) {
+ paintMissingPluginIcon(context, rect);
+ return;
+ }
+
+ if (context->paintingDisabled())
+ return;
+ m_npWindow.ws_info = (void*)(context->platformContext());
+ setNPWindowIfNeeded();
+
+ if (m_isWindowed && platformPluginWidget())
+ static_cast<PluginContainerSymbian*>(platformPluginWidget())->adjustGeometry();
+
+ if (m_isWindowed)
+ return;
+
+ context->save();
+ IntRect clipRect(rect);
+ clipRect.intersect(frameRect());
+ context->clip(clipRect);
+ context->translate(frameRect().location().x(), frameRect().location().y());
+
+ QPaintEvent ev(rect);
+ QEvent& npEvent = ev;
+ dispatchNPEvent(npEvent);
+
+ context->restore();
+}
+
+// TODO: Unify across ports.
+bool PluginView::dispatchNPEvent(NPEvent& event)
+{
+ if (!m_plugin->pluginFuncs()->event)
+ return false;
+
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+
+ setCallingPlugin(true);
+ bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+
+ return accepted;
+}
+
+void PluginView::handleKeyboardEvent(KeyboardEvent* event)
+{
+ if (m_isWindowed)
+ return;
+
+ ASSERT(event->keyEvent()->qtEvent());
+ QEvent& npEvent = *(event->keyEvent()->qtEvent());
+ if (!dispatchNPEvent(npEvent))
+ event->setDefaultHandled();
+}
+
+void PluginView::handleMouseEvent(MouseEvent* event)
+{
+ if (m_isWindowed)
+ return;
+
+ if (event->type() == eventNames().mousedownEvent) {
+ // Give focus to the plugin on click
+ if (Page* page = m_parentFrame->page())
+ page->focusController()->setActive(true);
+
+ focusPluginElement();
+ }
+
+ QEvent::Type type;
+ if (event->type() == eventNames().mousedownEvent)
+ type = QEvent::MouseButtonPress;
+ else if (event->type() == eventNames().mousemoveEvent)
+ type = QEvent::MouseMove;
+ else if (event->type() == eventNames().mouseupEvent)
+ type = QEvent::MouseButtonRelease;
+ else
+ return;
+
+ QPoint position(event->offsetX(), event->offsetY());
+ Qt::MouseButton button;
+ switch (event->which()) {
+ case 1:
+ button = Qt::LeftButton;
+ break;
+ case 2:
+ button = Qt::MidButton;
+ break;
+ case 3:
+ button = Qt::RightButton;
+ break;
+ default:
+ button = Qt::NoButton;
+ }
+ Qt::KeyboardModifiers modifiers = 0;
+ if (event->ctrlKey())
+ modifiers |= Qt::ControlModifier;
+ if (event->altKey())
+ modifiers |= Qt::AltModifier;
+ if (event->shiftKey())
+ modifiers |= Qt::ShiftModifier;
+ if (event->metaKey())
+ modifiers |= Qt::MetaModifier;
+ QMouseEvent mouseEvent(type, position, button, button, modifiers);
+ QEvent& npEvent = mouseEvent;
+ if (!dispatchNPEvent(npEvent))
+ event->setDefaultHandled();
+}
+
+void PluginView::setParent(ScrollView* parent)
+{
+ Widget::setParent(parent);
+
+ if (parent) {
+ init();
+ if (m_status == PluginStatusLoadedSuccessfully)
+ updatePluginWidget();
+ }
+}
+
+void PluginView::setNPWindowRect(const IntRect&)
+{
+ if (!m_isWindowed)
+ setNPWindowIfNeeded();
+}
+
+void PluginView::setNPWindowIfNeeded()
+{
+ if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
+ return;
+ if (m_isWindowed) {
+ ASSERT(platformPluginWidget());
+ platformPluginWidget()->setGeometry(m_windowRect);
+ // if setMask is set with an empty QRegion, no clipping will
+ // be performed, so in that case we hide the plugin view
+ platformPluginWidget()->setVisible(!m_clipRect.isEmpty());
+ platformPluginWidget()->setMask(QRegion(m_clipRect));
+
+ m_npWindow.x = m_windowRect.x();
+ m_npWindow.y = m_windowRect.y();
+
+ m_npWindow.clipRect.left = max(0, m_clipRect.x());
+ m_npWindow.clipRect.top = max(0, m_clipRect.y());
+ m_npWindow.clipRect.right = m_clipRect.x() + m_clipRect.width();
+ m_npWindow.clipRect.bottom = m_clipRect.y() + m_clipRect.height();
+
+ } else {
+ // always call this method before painting.
+ m_npWindow.x = 0;
+ m_npWindow.y = 0;
+
+ m_npWindow.clipRect.left = 0;
+ m_npWindow.clipRect.top = 0;
+ m_npWindow.clipRect.right = m_windowRect.width();
+ m_npWindow.clipRect.bottom = m_windowRect.height();
+ m_npWindow.window = 0;
+ }
+
+ m_npWindow.width = m_windowRect.width();
+ m_npWindow.height = m_windowRect.height();
+
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+}
+
+void PluginView::setParentVisible(bool visible)
+{
+ if (isParentVisible() == visible)
+ return;
+
+ Widget::setParentVisible(visible);
+
+ if (isSelfVisible() && platformPluginWidget())
+ platformPluginWidget()->setVisible(visible);
+}
+
+NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
+{
+ notImplemented();
+ return NPERR_NO_ERROR;
+}
+
+bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
+{
+ switch (variable) {
+ case NPNVjavascriptEnabledBool:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVSupportsWindowless:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool PluginView::platformGetValue(NPNVariable, void*, NPError*)
+{
+ return false;
+}
+
+void PluginView::invalidateRect(const IntRect& rect)
+{
+ if (m_isWindowed) {
+ platformWidget()->update(rect);
+ return;
+ }
+
+ invalidateWindowlessPluginRect(rect);
+}
+
+void PluginView::invalidateRect(NPRect* rect)
+{
+ if (m_isWindowed)
+ return;
+ if (!rect) {
+ invalidate();
+ return;
+ }
+ IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
+ m_invalidRects.append(r);
+ if (!m_invalidateTimer.isActive())
+ m_invalidateTimer.startOneShot(0.001);
+}
+
+void PluginView::invalidateRegion(NPRegion region)
+{
+ if (m_isWindowed)
+ return;
+
+ if (!region)
+ return;
+
+ QVector<QRect> rects = region->rects();
+ for (int i = 0; i < rects.size(); ++i) {
+ const QRect& qRect = rects.at(i);
+ m_invalidRects.append(qRect);
+ if (!m_invalidateTimer.isActive())
+ m_invalidateTimer.startOneShot(0.001);
+ }
+}
+
+void PluginView::forceRedraw()
+{
+ if (m_isWindowed)
+ return;
+ invalidate();
+}
+
+bool PluginView::platformStart()
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_status == PluginStatusLoadedSuccessfully);
+
+ show();
+
+ if (m_isWindowed) {
+ QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient();
+ QGraphicsProxyWidget* proxy = 0;
+ if (QGraphicsWebView *webView = qobject_cast<QGraphicsWebView*>(client->pluginParent()))
+ proxy = new QGraphicsProxyWidget(webView);
+
+ PluginContainerSymbian* container = new PluginContainerSymbian(this, proxy ? 0 : client->ownerWidget(), proxy);
+ setPlatformWidget(container);
+ if (proxy)
+ proxy->setWidget(container);
+
+ m_npWindow.type = NPWindowTypeWindow;
+ m_npWindow.window = (void*)platformPluginWidget();
+
+ } else {
+ setPlatformWidget(0);
+ m_npWindow.type = NPWindowTypeDrawable;
+ m_npWindow.window = 0; // Not used?
+ }
+ updatePluginWidget();
+ setNPWindowIfNeeded();
+
+ return true;
+}
+
+void PluginView::platformDestroy()
+{
+ if (platformPluginWidget()) {
+ PluginContainerSymbian* container = static_cast<PluginContainerSymbian*>(platformPluginWidget());
+ if (container && container->proxy())
+ delete container->proxy();
+ else
+ delete container;
+ }
+}
+
+void PluginView::halt()
+{
+}
+
+void PluginView::restart()
+{
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/plugins/symbian/npinterface.h b/Source/WebCore/plugins/symbian/npinterface.h
new file mode 100644
index 0000000..e296127
--- /dev/null
+++ b/Source/WebCore/plugins/symbian/npinterface.h
@@ -0,0 +1,37 @@
+/*
+ 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.
+*/
+#ifndef npinterface_h
+#define npinterface_h
+
+#include "npfunctions.h"
+#include <QtPlugin>
+
+class NPInterface {
+public:
+ virtual NPError NP_Initialize(NPNetscapeFuncs* aNPNFuncs, NPPluginFuncs* aNPPFuncs) = 0;
+ virtual void NP_Shutdown() = 0;
+ virtual char* NP_GetMIMEDescription() = 0;
+};
+
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_INTERFACE(NPInterface, "com.nokia.qts60.webplugin/1.0");
+QT_END_NAMESPACE
+
+#endif // npinterface_h
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
diff --git a/Source/WebCore/plugins/wx/PluginDataWx.cpp b/Source/WebCore/plugins/wx/PluginDataWx.cpp
new file mode 100644
index 0000000..0eb890f
--- /dev/null
+++ b/Source/WebCore/plugins/wx/PluginDataWx.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> 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 "PluginData.h"
+
+#include "NotImplemented.h"
+#include "PluginDatabase.h"
+#include "PluginPackage.h"
+
+namespace WebCore {
+
+void PluginData::initPlugins(const Page*)
+{
+ PluginDatabase* db = PluginDatabase::installedPlugins();
+ const Vector<PluginPackage*> &plugins = db->plugins();
+
+ for (unsigned int i = 0; i < plugins.size(); ++i) {
+ PluginInfo info;
+ 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;
+
+ mime.type = it->first;
+ mime.desc = it->second;
+ mime.extensions = package->mimeToExtensions().get(mime.type);
+
+ info.mimes.append(mime);
+ }
+
+ m_plugins.append(info);
+ }
+}
+
+void PluginData::refresh()
+{
+ notImplemented();
+}
+
+};