diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
commit | 1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch) | |
tree | 4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /WebCore/plugins | |
parent | 9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff) | |
download | external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'WebCore/plugins')
59 files changed, 6771 insertions, 4005 deletions
diff --git a/WebCore/plugins/MimeType.cpp b/WebCore/plugins/MimeType.cpp new file mode 100644 index 0000000..c4b051c --- /dev/null +++ b/WebCore/plugins/MimeType.cpp @@ -0,0 +1,70 @@ +/* + * 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 "MimeType.h" + +#include "Frame.h" +#include "Page.h" +#include "Plugin.h" +#include "PluginData.h" +#include "Settings.h" + +namespace WebCore { + +MimeType::MimeType(PassRefPtr<PluginData> pluginData, unsigned index) + : m_pluginData(pluginData) + , m_index(index) +{ +} + +MimeType::~MimeType() +{ +} + +const String &MimeType::type() const +{ + return m_pluginData->mimes()[m_index]->type; +} + +const String &MimeType::suffixes() const +{ + return m_pluginData->mimes()[m_index]->suffixes; +} + +const String &MimeType::description() const +{ + return m_pluginData->mimes()[m_index]->desc; +} + +PassRefPtr<Plugin> MimeType::enabledPlugin() const +{ + const Page* p = m_pluginData->page(); + if (!p || !p->settings()->arePluginsEnabled()) + return 0; + + const PluginInfo *info = m_pluginData->mimes()[m_index]->plugin; + const Vector<PluginInfo*>& plugins = m_pluginData->plugins(); + for (size_t i = 0; i < plugins.size(); ++i) { + if (plugins[i] == info) + return Plugin::create(m_pluginData.get(), i); + } + return 0; +} + +} // namespace WebCore diff --git a/WebCore/plugins/MimeType.h b/WebCore/plugins/MimeType.h new file mode 100644 index 0000000..5207918 --- /dev/null +++ b/WebCore/plugins/MimeType.h @@ -0,0 +1,52 @@ +/* + 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 MimeType_h +#define MimeType_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/RefCounted.h> + +#include "PluginData.h" + +namespace WebCore { + + class Plugin; + class String; + + class MimeType : public RefCounted<MimeType> { + public: + static PassRefPtr<MimeType> create(PassRefPtr<PluginData> pluginData, unsigned index) { return adoptRef(new MimeType(pluginData, index)); } + ~MimeType(); + + const String &type() const; + const String &suffixes() const; + const String &description() const; + PassRefPtr<Plugin> enabledPlugin() const; + + private: + MimeType(PassRefPtr<PluginData>, unsigned index); + RefPtr<PluginData> m_pluginData; + unsigned m_index; + }; + +} + +#endif diff --git a/WebCore/plugins/MimeType.idl b/WebCore/plugins/MimeType.idl new file mode 100644 index 0000000..ac75cc2 --- /dev/null +++ b/WebCore/plugins/MimeType.idl @@ -0,0 +1,29 @@ +/* + 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. +*/ + +module window { + + interface MimeType { + readonly attribute DOMString type; + readonly attribute DOMString suffixes; + readonly attribute DOMString description; + readonly attribute Plugin enabledPlugin; + }; + +} diff --git a/WebCore/plugins/MimeTypeArray.cpp b/WebCore/plugins/MimeTypeArray.cpp new file mode 100644 index 0000000..9bc4fcf --- /dev/null +++ b/WebCore/plugins/MimeTypeArray.cpp @@ -0,0 +1,94 @@ +/* + * 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 "MimeTypeArray.h" + +#include "AtomicString.h" +#include "Frame.h" +#include "Page.h" +#include "Plugin.h" +#include "PluginData.h" + +namespace WebCore { + +MimeTypeArray::MimeTypeArray(Frame* frame) + : m_frame(frame) +{ +} + +MimeTypeArray::~MimeTypeArray() +{ +} + +unsigned MimeTypeArray::length() const +{ + PluginData* data = getPluginData(); + if (!data) + return 0; + return data->mimes().size(); +} + +PassRefPtr<MimeType> MimeTypeArray::item(unsigned index) +{ + PluginData* data = getPluginData(); + if (!data) + return 0; + const Vector<MimeClassInfo*>& mimes = data->mimes(); + if (index >= mimes.size()) + return 0; + return MimeType::create(data, index).get(); +} + +bool MimeTypeArray::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<MimeType> MimeTypeArray::nameGetter(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 MimeType::create(data, i).get(); + } + return 0; +} + +PluginData* MimeTypeArray::getPluginData() const +{ + if (!m_frame) + return 0; + Page* p = m_frame->page(); + if (!p) + return 0; + return p->pluginData(); +} + +} // namespace WebCore diff --git a/WebCore/plugins/MimeTypeArray.h b/WebCore/plugins/MimeTypeArray.h new file mode 100644 index 0000000..392a812 --- /dev/null +++ b/WebCore/plugins/MimeTypeArray.h @@ -0,0 +1,60 @@ +/* + 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 MimeTypeArray_h +#define MimeTypeArray_h + +#include "MimeType.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace JSC { + class ExecState; +}; + +namespace WebCore { + + class AtomicString; + class Frame; + class PluginData; + + // FIXME: Generated JSMimeTypeArray.cpp doesn't include JSMimeType.h for toJS + JSC::JSValue* toJS(JSC::ExecState*, MimeType*); + + class MimeTypeArray : public RefCounted<MimeTypeArray> { + public: + static PassRefPtr<MimeTypeArray> create(Frame* frame) { return adoptRef(new MimeTypeArray(frame)); } + ~MimeTypeArray(); + + void disconnectFrame() { m_frame = 0; } + + unsigned length() const; + PassRefPtr<MimeType> item(unsigned index); + bool canGetItemsForName(const AtomicString& propertyName); + PassRefPtr<MimeType> nameGetter(const AtomicString& propertyName); + private: + MimeTypeArray(Frame*); + PluginData* getPluginData() const; + + Frame* m_frame; + }; +} + +#endif diff --git a/WebCore/plugins/MimeTypeArray.idl b/WebCore/plugins/MimeTypeArray.idl new file mode 100644 index 0000000..067f2a8 --- /dev/null +++ b/WebCore/plugins/MimeTypeArray.idl @@ -0,0 +1,26 @@ +/* + 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. +*/ + +module window { + + interface [HasNameGetter, HasIndexGetter] MimeTypeArray { + readonly attribute unsigned long length; + }; + +} diff --git a/WebCore/plugins/Plugin.cpp b/WebCore/plugins/Plugin.cpp new file mode 100644 index 0000000..d095c55 --- /dev/null +++ b/WebCore/plugins/Plugin.cpp @@ -0,0 +1,91 @@ +/* + * 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 "Plugin.h" + +#include "AtomicString.h" +#include "PluginData.h" +#include "Frame.h" + +namespace WebCore { + +Plugin::Plugin(PluginData* pluginData, unsigned index) + : m_pluginData(pluginData) + , m_index(index) +{ +} + +Plugin::~Plugin() +{ +} + +String Plugin::name() const +{ + return m_pluginData->plugins()[m_index]->name; +} + +String Plugin::filename() const +{ + return m_pluginData->plugins()[m_index]->file; +} + +String Plugin::description() const +{ + return m_pluginData->plugins()[m_index]->desc; +} + +unsigned Plugin::length() const +{ + return m_pluginData->plugins()[m_index]->mimes.size(); +} + +PassRefPtr<MimeType> Plugin::item(unsigned index) +{ + const Vector<PluginInfo*>& plugins = m_pluginData->plugins(); + if (index >= plugins[m_index]->mimes.size()) + return 0; + + MimeClassInfo* mime = plugins[m_index]->mimes[index]; + + const Vector<MimeClassInfo*>& mimes = m_pluginData->mimes(); + for (unsigned i = 0; i < mimes.size(); ++i) + if (mimes[i] == mime) + return MimeType::create(m_pluginData.get(), i).get(); + return 0; +} + +bool Plugin::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<MimeType> Plugin::nameGetter(const AtomicString& propertyName) +{ + const Vector<MimeClassInfo*>& mimes = m_pluginData->mimes(); + for (unsigned i = 0; i < mimes.size(); ++i) + if (mimes[i]->type == propertyName) + return MimeType::create(m_pluginData.get(), i).get(); + return 0; +} + +} // namespace WebCore diff --git a/WebCore/plugins/Plugin.h b/WebCore/plugins/Plugin.h new file mode 100644 index 0000000..1d1384a --- /dev/null +++ b/WebCore/plugins/Plugin.h @@ -0,0 +1,65 @@ +/* + 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 Plugin_h +#define Plugin_h + +#include "MimeType.h" +#include <wtf/RefPtr.h> +#include <wtf/RefCounted.h> + +namespace JSC { + class ExecState; +} + +namespace WebCore { + + class AtomicString; + class Plugin; + class String; + + // FIXME: Generated JSPlugin.cpp doesn't include JSMimeType.h for toJS + JSC::JSValue* toJS(JSC::ExecState*, MimeType*); + + class PluginData; + + class Plugin : public RefCounted<Plugin> { + public: + static PassRefPtr<Plugin> create(PluginData* pluginData, unsigned index) { return adoptRef(new Plugin(pluginData, index)); } + ~Plugin(); + + String name() const; + String filename() const; + String description() const; + + unsigned length() const; + + PassRefPtr<MimeType> item(unsigned index); + bool canGetItemsForName(const AtomicString& propertyName); + PassRefPtr<MimeType> nameGetter(const AtomicString& propertyName); + + private: + Plugin(PluginData*, unsigned index); + RefPtr<PluginData> m_pluginData; + unsigned m_index; + }; + +} + +#endif diff --git a/WebCore/plugins/Plugin.idl b/WebCore/plugins/Plugin.idl new file mode 100644 index 0000000..988f371 --- /dev/null +++ b/WebCore/plugins/Plugin.idl @@ -0,0 +1,29 @@ +/* + 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. +*/ + +module window { + + interface [HasNameGetter, HasIndexGetter] Plugin { + readonly attribute DOMString name; + readonly attribute DOMString filename; + readonly attribute DOMString description; + readonly attribute unsigned long length; + }; + +} diff --git a/WebCore/plugins/PluginArray.cpp b/WebCore/plugins/PluginArray.cpp new file mode 100644 index 0000000..d304829 --- /dev/null +++ b/WebCore/plugins/PluginArray.cpp @@ -0,0 +1,99 @@ +/* + * 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 "PluginArray.h" + +#include "AtomicString.h" +#include "Frame.h" +#include "Page.h" +#include "Plugin.h" +#include "PluginData.h" + +namespace WebCore { + +PluginArray::PluginArray(Frame* frame) + : m_frame(frame) +{ +} + +PluginArray::~PluginArray() +{ +} + +unsigned PluginArray::length() const +{ + PluginData* data = getPluginData(); + if (!data) + return 0; + return data->plugins().size(); +} + +PassRefPtr<Plugin> PluginArray::item(unsigned index) +{ + PluginData* data = getPluginData(); + if (!data) + return 0; + const Vector<PluginInfo*>& plugins = data->plugins(); + if (index >= plugins.size()) + return 0; + return Plugin::create(data, index).get(); +} + +bool PluginArray::canGetItemsForName(const AtomicString& propertyName) +{ + PluginData* data = getPluginData(); + 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<Plugin> PluginArray::nameGetter(const AtomicString& propertyName) +{ + PluginData* data = getPluginData(); + if (!data) + return 0; + const Vector<PluginInfo*>& plugins = data->plugins(); + for (unsigned i = 0; i < plugins.size(); ++i) { + if (plugins[i]->name == propertyName) + return Plugin::create(data, i).get(); + } + return 0; +} + +void PluginArray::refresh(bool reload) +{ + Page::refreshPlugins(reload); +} + +PluginData* PluginArray::getPluginData() const +{ + if (!m_frame) + return 0; + Page* p = m_frame->page(); + if (!p) + return 0; + return p->pluginData(); +} + +} // namespace WebCore diff --git a/WebCore/plugins/PluginArray.h b/WebCore/plugins/PluginArray.h new file mode 100644 index 0000000..e51775d --- /dev/null +++ b/WebCore/plugins/PluginArray.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 PluginArray_h +#define PluginArray_h + +#include "Plugin.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace JSC { + class ExecState; +} + +namespace WebCore { + + class AtomicString; + class Frame; + class PluginData; + + // FIXME: Generated JSPluginArray.cpp doesn't include JSPlugin.h for toJS + JSC::JSValue* toJS(JSC::ExecState*, Plugin*); + + class PluginArray : public RefCounted<PluginArray> { + public: + static PassRefPtr<PluginArray> create(Frame* frame) { return adoptRef(new PluginArray(frame)); } + ~PluginArray(); + + void disconnectFrame() { m_frame = 0; } + + unsigned length() const; + PassRefPtr<Plugin> item(unsigned index); + bool canGetItemsForName(const AtomicString& propertyName); + PassRefPtr<Plugin> nameGetter(const AtomicString& propertyName); + + void refresh(bool reload); + private: + PluginArray(Frame*); + PluginData* getPluginData() const; + + Frame* m_frame; + }; +} + +#endif diff --git a/WebCore/plugins/PluginArray.idl b/WebCore/plugins/PluginArray.idl new file mode 100644 index 0000000..58f68b5 --- /dev/null +++ b/WebCore/plugins/PluginArray.idl @@ -0,0 +1,27 @@ +/* + 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. +*/ + +module window { + + interface [HasNameGetter, HasIndexGetter] PluginArray { + readonly attribute unsigned long length; + void refresh(in boolean reload); + }; + +} diff --git a/WebCore/plugins/PluginData.cpp b/WebCore/plugins/PluginData.cpp new file mode 100644 index 0000000..ca4bda5 --- /dev/null +++ b/WebCore/plugins/PluginData.cpp @@ -0,0 +1,63 @@ +/* + 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" + +namespace WebCore { + +PluginData::PluginData(const Page* page) + : m_page(page) +{ + initPlugins(); + + 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]); + } +} + +PluginData::~PluginData() +{ + deleteAllValues(m_plugins); + deleteAllValues(m_mimes); +} + +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) + if (m_mimes[i]->type == mimeType) + return m_mimes[i]->plugin->name; + return String(); +} + +} diff --git a/WebCore/plugins/PluginData.h b/WebCore/plugins/PluginData.h new file mode 100644 index 0000000..b2866bf --- /dev/null +++ b/WebCore/plugins/PluginData.h @@ -0,0 +1,74 @@ +/* + 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; + String suffixes; + PluginInfo* plugin; + }; + + 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)); } + ~PluginData(); + + void disconnectPage() { m_page = 0; } + const Page* page() const { return m_page; } + + const Vector<PluginInfo*>& plugins() const { return m_plugins; } + const Vector<MimeClassInfo*>& mimes() const { return m_mimes; } + + bool supportsMimeType(const String& mimeType) const; + String pluginNameForMimeType(const String& mimeType) const; + + static void refresh(); + + private: + PluginData(const Page*); + void initPlugins(); + + Vector<PluginInfo*> m_plugins; + Vector<MimeClassInfo*> m_mimes; + const Page* m_page; + }; + +} + +#endif diff --git a/WebCore/plugins/PluginDatabase.cpp b/WebCore/plugins/PluginDatabase.cpp new file mode 100644 index 0000000..e3b86ae --- /dev/null +++ b/WebCore/plugins/PluginDatabase.cpp @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PluginDatabase.h" + +#include "Frame.h" +#include "KURL.h" +#include "PluginPackage.h" +#include <stdlib.h> + +namespace WebCore { + +PluginDatabase* PluginDatabase::installedPlugins() +{ + static PluginDatabase* plugins = 0; + + if (!plugins) { + plugins = new PluginDatabase; + plugins->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() +{ + 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; + + 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_end = (*it)->mimeToDescriptions().end(); + for (MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin(); map_it != map_end; ++map_it) { + m_registeredMIMETypes.add(map_it->first); + } + } + + return 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(); + + Vector<PluginPackage*, 2> pluginChoices; + + for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { + if ((*it)->mimeToDescriptions().contains(key)) + pluginChoices.append((*it).get()); + } + + if (pluginChoices.isEmpty()) + return 0; + + qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare); + + return pluginChoices[0]; +} + +String PluginDatabase::MIMETypeForExtension(const String& extension) const +{ + if (extension.isEmpty()) + return String(); + + PluginSet::const_iterator end = m_plugins.end(); + String mimeType; + Vector<PluginPackage*, 2> pluginChoices; + HashMap<PluginPackage*, String> mimeTypeForPlugin; + + for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { + MIMEToExtensionsMap::const_iterator mime_end = (*it)->mimeToExtensions().end(); + + for (MIMEToExtensionsMap::const_iterator mime_it = (*it)->mimeToExtensions().begin(); mime_it != mime_end; ++mime_it) { + const Vector<String>& extensions = mime_it->second; + bool foundMapping = false; + for (unsigned i = 0; i < extensions.size(); i++) { + if (equalIgnoringCase(extensions[i], extension)) { + PluginPackage* plugin = (*it).get(); + pluginChoices.append(plugin); + mimeTypeForPlugin.add(plugin, mime_it->first); + foundMapping = true; + break; + } + } + if (foundMapping) + break; + } + } + + if (pluginChoices.isEmpty()) + return String(); + + qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare); + + return mimeTypeForPlugin.get(pluginChoices[0]); +} + +PluginPackage* PluginDatabase::findPlugin(const KURL& url, String& mimeType) +{ + PluginPackage* plugin = pluginForMIMEType(mimeType); + String filename = url.string(); + + if (!plugin) { + String filename = url.lastPathComponent(); + if (!filename.endsWith("/")) { + int extensionPos = filename.reverseFind('.'); + if (extensionPos != -1) { + String extension = filename.substring(extensionPos + 1); + + mimeType = MIMETypeForExtension(extension); + plugin = pluginForMIMEType(mimeType); + } + } + } + + // FIXME: if no plugin could be found, query Windows for the mime type + // corresponding to the extension. + + return plugin; +} + +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) +{ + m_plugins.remove(package); + m_pluginsByPath.remove(package->path()); +} + +#if !PLATFORM(WIN_OS) || PLATFORM(WX) +// 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"); + + 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(getenv("QTWEBKIT_PLUGIN_PATH")); + qtPath.split(UChar(':'), /* allowEmptyEntries */ false, qtPaths); + paths.append(qtPaths); +#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 // !PLATFORM(WIN_OS) + +} diff --git a/WebCore/plugins/PluginDatabase.h b/WebCore/plugins/PluginDatabase.h index 71181b0..ccb3821 100644 --- a/WebCore/plugins/PluginDatabase.h +++ b/WebCore/plugins/PluginDatabase.h @@ -1,5 +1,6 @@ /* * 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 @@ -26,22 +27,18 @@ #ifndef PluginDatabase_H #define PluginDatabase_H -#ifdef ANDROID_PLUGINS - -#include "PluginDatabaseAndroid.h" - -namespace WebCore { - typedef PluginDatabaseAndroid PluginDatabase; -} - -#else // !defined(ANDROID_PLUGINS) +#include "PlatformString.h" +#include "PluginPackage.h" +#include "StringHash.h" #include <wtf/Vector.h> #include <wtf/HashSet.h> -#include "PlatformString.h" -#include "PluginPackage.h" -#include "StringHash.h" +#if defined(ANDROID_PLUGINS) +namespace android { + class WebSettings; +} +#endif namespace WebCore { class Element; @@ -49,36 +46,51 @@ namespace WebCore { class IntSize; class KURL; class PluginPackage; - class PluginView; typedef HashSet<RefPtr<PluginPackage>, PluginPackageHash> PluginSet; class PluginDatabase { public: static PluginDatabase* installedPlugins(); - PluginView* createPluginView(Frame* parentFrame, const IntSize&, Element* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually); bool refresh(); Vector<PluginPackage*> plugins() const; bool isMIMETypeRegistered(const String& mimeType); - void addExtraPluginPath(const String&); + void addExtraPluginDirectory(const String&); + + static bool isPreferredPluginDirectory(const String& directory); + static int preferredPluginCompare(const void*, const void*); + + PluginPackage* findPlugin(const KURL&, String& mimeType); + private: - void setPluginPaths(const Vector<String>& paths) { m_pluginPaths = paths; } - PluginSet getPluginsInPaths() const; + void setPluginDirectories(const Vector<String>& directories) { m_pluginDirectories = directories; } + + 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*); - PluginPackage* findPlugin(const KURL& url, String& mimeType); PluginPackage* pluginForMIMEType(const String& mimeType); String MIMETypeForExtension(const String& extension) const; - static Vector<String> defaultPluginPaths(); + static Vector<String> defaultPluginDirectories(); - Vector<String> m_pluginPaths; + 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 }; } // namespace WebCore -#endif // !defined(ANDROID_PLUGINS) - #endif diff --git a/WebCore/plugins/PluginDebug.h b/WebCore/plugins/PluginDebug.h index 31d9891..a57c209 100644 --- a/WebCore/plugins/PluginDebug.h +++ b/WebCore/plugins/PluginDebug.h @@ -23,13 +23,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef PLUGIN_DEBUG_H__ -#define PLUGIN_DEBUG_H__ +#ifndef PluginDebug_h +#define PluginDebug_h #include "Logging.h" #include "npruntime_internal.h" -static const char* errorStrings[] = { +#if !LOG_DISABLED + +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 */ @@ -47,6 +49,8 @@ static const char* errorStrings[] = { "Unknown error code" }; +#endif + #define LOG_NPERROR(err) if (err != NPERR_NO_ERROR) LOG_VERBOSE(Plugin, "%s\n", errorStrings[err]) #define LOG_PLUGIN_NET_ERROR() LOG_VERBOSE(Plugin, "Stream failed due to problems with network, disk I/O, lack of memory, or other problems.\n") diff --git a/WebCore/plugins/PluginInfoStore.cpp b/WebCore/plugins/PluginInfoStore.cpp index d95ba9e..732a1e1 100644 --- a/WebCore/plugins/PluginInfoStore.cpp +++ b/WebCore/plugins/PluginInfoStore.cpp @@ -25,6 +25,9 @@ #include "config.h" #include "PluginInfoStore.h" + +#include "KURL.h" +#include "PluginData.h" #include "PluginDatabase.h" #include "PluginPackage.h" @@ -71,7 +74,14 @@ unsigned PluginInfoStore::pluginCount() const String PluginInfoStore::pluginNameForMIMEType(const String& mimeType) { - // FIXME 5629139: Implement this method on Windows. + String mimeTypeCopy(mimeType); + + if (PluginPackage* package = PluginDatabase::installedPlugins()->findPlugin(KURL(), mimeTypeCopy)) { + ASSERT(mimeType == mimeTypeCopy); + + return package->name(); + } + return String(); } diff --git a/WebCore/plugins/PluginInfoStore.h b/WebCore/plugins/PluginInfoStore.h index 7471015..302cf8c 100644 --- a/WebCore/plugins/PluginInfoStore.h +++ b/WebCore/plugins/PluginInfoStore.h @@ -33,20 +33,6 @@ namespace WebCore { struct PluginInfo; -struct MimeClassInfo { - String type; - String desc; - String suffixes; - PluginInfo* plugin; -}; - -struct PluginInfo { - String name; - String file; - String desc; - Vector<MimeClassInfo*> mimes; -}; - class PluginInfoStore { public: PluginInfo *createPluginInfoForPluginAtIndex(unsigned); diff --git a/WebCore/plugins/PluginMainThreadScheduler.cpp b/WebCore/plugins/PluginMainThreadScheduler.cpp new file mode 100644 index 0000000..a7067f1 --- /dev/null +++ b/WebCore/plugins/PluginMainThreadScheduler.cpp @@ -0,0 +1,115 @@ +/* + * 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" + +namespace WebCore { + +PluginMainThreadScheduler& PluginMainThreadScheduler::scheduler() +{ + static PluginMainThreadScheduler& scheduler = *new PluginMainThreadScheduler; + + 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/WebCore/plugins/PluginMainThreadScheduler.h b/WebCore/plugins/PluginMainThreadScheduler.h new file mode 100644 index 0000000..8872d56 --- /dev/null +++ b/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: + 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/WebCore/plugins/PluginPackage.cpp b/WebCore/plugins/PluginPackage.cpp new file mode 100644 index 0000000..f3c9075 --- /dev/null +++ b/WebCore/plugins/PluginPackage.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PluginPackage.h" + +#include "CString.h" +#include "MIMETypeRegistry.h" +#include "PluginDatabase.h" +#include "PluginDebug.h" +#include "Timer.h" +#include "npruntime_impl.h" +#include <string.h> +#include <wtf/OwnArrayPtr.h> + +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 == 0) + unloadWithoutShutdown(); + else + unload(); + + ASSERT(!m_isLoaded); +} + +void PluginPackage::freeLibrarySoon() +{ + ASSERT(!m_freeLibraryTimer.isActive()); + ASSERT(m_module); + ASSERT(m_loadCount == 0); + +#ifdef ANDROID_PLUGINS + // TODO(jripley): Timer<T> is broken. Unload immediately for now. + unloadModule(m_module); + m_module = 0; +#else + m_freeLibraryTimer.startOneShot(0); +#endif +} + +void PluginPackage::freeLibraryTimerFired(Timer<PluginPackage>*) +{ + ASSERT(m_module); + ASSERT(m_loadCount == 0); + + 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; + + if (diff = compareFileVersion(compareTo.version())) + return diff; + + return strcmp(parentDirectory().utf8().data(), compareTo.parentDirectory().utf8().data()); +} + +PluginPackage::PluginPackage(const String& path, const time_t& lastModified) + : m_isLoaded(false) + , m_loadCount(0) + , m_path(path) + , m_moduleVersion(0) + , m_module(0) + , m_lastModified(lastModified) + , m_freeLibraryTimer(this, &PluginPackage::freeLibraryTimerFired) +{ + m_fileName = pathGetFileName(m_path); + m_parentDirectory = m_path.left(m_path.length() - m_fileName.length() - 1); +} + +void PluginPackage::unload() +{ + if (!m_isLoaded) + return; + + if (--m_loadCount > 0) + return; + + m_NPP_Shutdown(); + + unloadWithoutShutdown(); +} + +void PluginPackage::unloadWithoutShutdown() +{ + if (!m_isLoaded) + return; + + ASSERT(m_loadCount == 0); + ASSERT(m_module); + +#if defined(ANDROID_PLUGINS) + // Remove the Java object from PluginList. + unregisterPluginObject(); +#endif + + // <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; +} + +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(); +} + +} diff --git a/WebCore/plugins/PluginPackage.h b/WebCore/plugins/PluginPackage.h index ab15e33..4cf5e9e 100644 --- a/WebCore/plugins/PluginPackage.h +++ b/WebCore/plugins/PluginPackage.h @@ -1,5 +1,6 @@ /* * 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 @@ -26,25 +27,17 @@ #ifndef PluginPackage_H #define PluginPackage_H -#ifdef ANDROID_PLUGINS - -#include "PluginPackageAndroid.h" - -namespace WebCore { - typedef PluginPackageAndroid PluginPackage; -} - -#else !defined(ANDROID_PLUGINS) - -#include <winsock2.h> -#include <windows.h> - -#include "Timer.h" -#include "StringHash.h" +#include "FileSystem.h" #include "PlatformString.h" -#include "npfunctions.h" +#include "PluginQuirkSet.h" +#include "StringHash.h" +#include "Timer.h" +#include "npruntime_internal.h" #include <wtf/HashMap.h> #include <wtf/RefCounted.h> +#if defined(ANDROID_PLUGINS) +#include <nativehelper/jni.h> +#endif namespace WebCore { typedef HashMap<String, String> MIMEToDescriptionsMap; @@ -53,17 +46,19 @@ namespace WebCore { class PluginPackage : public RefCounted<PluginPackage> { public: ~PluginPackage(); - static PluginPackage* createPackage(const String& path, const FILETIME& lastModified); + static PassRefPtr<PluginPackage> createPackage(const String& path, const time_t& lastModified); - String name() const { return m_name; } - String description() const { return m_description; } - String fileName() const { return m_fileName; } - String parentDirectory() const { return m_parentDirectory; } + 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; } + time_t lastModified() const { return m_lastModified; } const MIMEToDescriptionsMap& mimeToDescriptions() const { return m_mimeToDescriptions; } const MIMEToExtensionsMap& mimeToExtensions() const { return m_mimeToExtensions; } - unsigned PluginPackage::hash() const; + unsigned hash() const; static bool equal(const PluginPackage& a, const PluginPackage& b); bool load(); @@ -71,31 +66,33 @@ namespace WebCore { void unloadWithoutShutdown(); const NPPluginFuncs* pluginFuncs() const { return &m_pluginFuncs; } + int compareFileVersion(const PlatformModuleVersion&) const; + int compare(const PluginPackage&) const; + PluginQuirkSet quirks() const { return m_quirks; } + const PlatformModuleVersion& version() const { return m_moduleVersion; } - int compareFileVersion(unsigned compareVersionMS, unsigned compareVersionLS) const; private: - PluginPackage(const String& path, const FILETIME& lastModified); + PluginPackage(const String& path, const time_t& lastModified); bool fetchInfo(); - void storeFileVersion(LPVOID versionInfoData); bool isPluginBlacklisted(); + void determineQuirks(const String& mimeType); bool m_isLoaded; int m_loadCount; - DWORD m_fileVersionMS; - DWORD m_fileVersionLS; - String m_description; String m_path; String m_fileName; String m_name; String m_parentDirectory; + PlatformModuleVersion m_moduleVersion; + MIMEToDescriptionsMap m_mimeToDescriptions; MIMEToExtensionsMap m_mimeToExtensions; - HMODULE m_module; - FILETIME m_lastModified; + PlatformModule m_module; + time_t m_lastModified; NPP_ShutdownProcPtr m_NPP_Shutdown; NPPluginFuncs m_pluginFuncs; @@ -104,29 +101,27 @@ namespace WebCore { void freeLibrarySoon(); void freeLibraryTimerFired(Timer<PluginPackage>*); Timer<PluginPackage> m_freeLibraryTimer; + + PluginQuirkSet m_quirks; + +#if defined(ANDROID_PLUGINS) + // Java Plugin object. + jobject m_pluginObject; + // Called from unloadWithoutShutdown() to remove the object + // from the PluginList. + void unregisterPluginObject(); +#endif }; struct PluginPackageHash { - static unsigned hash(const int key) { return reinterpret_cast<PluginPackage*>(key)->hash(); } + 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 int a, const int b) { return equal(reinterpret_cast<PluginPackage*>(a), reinterpret_cast<PluginPackage*>(b)); } + 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 -// FIXME: This is a workaround for a bug in WTF, where it's impossible to use a custom Hash function but with default traits. -// It should be possible to do this without a StorageTraits specialization. -namespace WTF { - template<> struct HashKeyStorageTraits<WebCore::PluginPackageHash, HashTraits<RefPtr<WebCore::PluginPackage> > > { - typedef IntTypes<sizeof(RefPtr<WebCore::PluginPackage>)>::SignedType IntType; - typedef WebCore::PluginPackageHash Hash; - typedef HashTraits<IntType> Traits; - }; -} - -#endif // !defined(ANDROID_PLUGINS) - #endif diff --git a/WebCore/plugins/PluginQuirkSet.h b/WebCore/plugins/PluginQuirkSet.h index 031baa0..e93f6e0 100644 --- a/WebCore/plugins/PluginQuirkSet.h +++ b/WebCore/plugins/PluginQuirkSet.h @@ -44,6 +44,7 @@ namespace WebCore { PluginQuirkFlashURLNotifyBug = 1 << 8, PluginQuirkDontClipToZeroRectWhenScrolling = 1 << 9, PluginQuirkDontSetNullWindowHandleOnDestroy = 1 << 10, + PluginQuirkDontAllowMultipleInstances = 1 << 11, }; class PluginQuirkSet { diff --git a/WebCore/plugins/PluginStream.cpp b/WebCore/plugins/PluginStream.cpp index a206b51..4bf2db4 100644 --- a/WebCore/plugins/PluginStream.cpp +++ b/WebCore/plugins/PluginStream.cpp @@ -129,14 +129,10 @@ void PluginStream::startStream() // Some plugins (Flash) expect that javascript URLs are passed back decoded as this is the // format used when requesting the URL. -#ifdef ANDROID_JAVASCRIPT_SECURITY if (responseURL.protocolIs("javascript")) -#else - if (responseURL.string().startsWith("javascript:", false)) -#endif - m_stream.url = strdup(responseURL.decode_string(responseURL.deprecatedString()).utf8()); + m_stream.url = strdup(decodeURLEscapeSequences(responseURL.string()).utf8().data()); else - m_stream.url = strdup(responseURL.deprecatedString().utf8()); + m_stream.url = strdup(responseURL.string().utf8().data()); CString mimeTypeStr = m_resourceResponse.mimeType().utf8(); @@ -146,12 +142,16 @@ void PluginStream::startStream() Vector<UChar> stringBuilder; String separator(": "); + String statusLine = String::format("HTTP %lu OK\n", m_resourceResponse.httpStatusCode()); + + 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((UChar)'\n'); + stringBuilder.append('\n'); } m_headers = String::adopt(stringBuilder).utf8(); @@ -191,10 +191,12 @@ void PluginStream::startStream() if (m_reason != WebReasonNone) return; - m_streamState = StreamStarted; - - if (npErr != NPERR_NO_ERROR) + if (npErr != NPERR_NO_ERROR) { cancelAndDestroyStream(npErr); + return; + } + + m_streamState = StreamStarted; if (m_transferMode == NP_NORMAL) return; @@ -238,8 +240,8 @@ void PluginStream::destroyStream() if (m_streamState == StreamStopped) return; - ASSERT (m_reason != WebReasonNone); - ASSERT (!m_deliveryData || m_deliveryData->size() == 0); + ASSERT(m_reason != WebReasonNone); + ASSERT(!m_deliveryData || m_deliveryData->size() == 0); closeFile(m_tempFileHandle); @@ -256,12 +258,17 @@ void PluginStream::destroyStream() m_loader->setDefersLoading(false); } - 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); + 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; } @@ -287,7 +294,7 @@ void PluginStream::destroyStream() // destructor, so reset it to 0 m_stream.url = 0; } - m_pluginFuncs->urlnotify(m_instance, m_resourceRequest.url().deprecatedString().utf8(), m_reason, m_notifyData); + m_pluginFuncs->urlnotify(m_instance, m_resourceRequest.url().string().utf8().data(), m_reason, m_notifyData); if (m_loader) m_loader->setDefersLoading(false); } @@ -452,4 +459,16 @@ void PluginStream::didFinishLoading(NetscapePlugInStreamLoader* loader) 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; +} + } diff --git a/WebCore/plugins/PluginStream.h b/WebCore/plugins/PluginStream.h index 6eb7b81..dc08f01 100644 --- a/WebCore/plugins/PluginStream.h +++ b/WebCore/plugins/PluginStream.h @@ -27,20 +27,9 @@ #ifndef PluginStream_H #define PluginStream_H -#ifdef ANDROID_PLUGINS - -#include "PluginStreamAndroid.h" - -namespace WebCore { - typedef PluginStreamAndroid PluginStream; -} - -#else // !defined(ANDROID_PLUGINS) - #include "CString.h" #include "FileSystem.h" #include "KURL.h" -#include "npfunctions.h" #include "NetscapePlugInStreamLoader.h" #include "PlatformString.h" #include "PluginQuirkSet.h" @@ -48,10 +37,11 @@ namespace WebCore { #include "ResourceResponse.h" #include "StringHash.h" #include "Timer.h" +#include "npruntime_internal.h" #include <wtf/HashMap.h> -#include <wtf/Vector.h> #include <wtf/OwnPtr.h> #include <wtf/RefCounted.h> +#include <wtf/Vector.h> namespace WebCore { class Frame; @@ -67,8 +57,11 @@ namespace WebCore { class PluginStream : public RefCounted<PluginStream>, private NetscapePlugInStreamLoaderClient { public: - PluginStream(PluginStreamClient*, Frame*, const ResourceRequest&, bool sendNotification, void* notifyData, const NPPluginFuncs*, NPP instance, const PluginQuirkSet&); - ~PluginStream(); + 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(); @@ -77,17 +70,21 @@ namespace WebCore { void setLoadManually(bool loadManually) { m_loadManually = loadManually; } + void sendJavaScriptStream(const KURL& requestURL, const 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; - void sendJavaScriptStream(const KURL& requestURL, const CString& resultString); - void cancelAndDestroyStream(NPReason); - - static NPP ownerForStream(NPStream*); private: + PluginStream(PluginStreamClient*, Frame*, const ResourceRequest&, bool sendNotification, void* notifyData, const NPPluginFuncs*, NPP instance, const PluginQuirkSet&); + void deliverData(); void destroyStream(NPReason); void destroyStream(); @@ -123,6 +120,4 @@ namespace WebCore { } // namespace WebCore -#endif // !defined(ANDROID_PLUGINS) - #endif diff --git a/WebCore/plugins/PluginView.cpp b/WebCore/plugins/PluginView.cpp new file mode 100644 index 0000000..459b11e --- /dev/null +++ b/WebCore/plugins/PluginView.cpp @@ -0,0 +1,922 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PluginView.h" + +#include "Document.h" +#include "DocumentLoader.h" +#include "Element.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "HTMLNames.h" +#include "HTMLPlugInElement.h" +#include "JSDOMWindow.h" +#include "KeyboardEvent.h" +#include "MIMETypeRegistry.h" +#include "MouseEvent.h" +#include "NotImplemented.h" +#include "Page.h" +#include "FocusController.h" +#include "PlatformMouseEvent.h" +#if PLATFORM(WIN_OS) && !PLATFORM(WX) && ENABLE(NETSCAPE_PLUGIN_API) +#include "PluginMessageThrottlerWin.h" +#endif +#include "PluginPackage.h" +#include "JSDOMBinding.h" +#include "ScriptController.h" +#include "PluginDatabase.h" +#include "PluginDebug.h" +#include "PluginMainThreadScheduler.h" +#include "PluginPackage.h" +#include "RenderObject.h" +#include "c_instance.h" +#include "npruntime_impl.h" +#include "runtime_root.h" +#include "Settings.h" +#include "runtime.h" +#include <runtime/JSLock.h> +#include <runtime/JSValue.h> +#include <wtf/ASCIICType.h> + +using JSC::ExecState; +using JSC::JSLock; +using JSC::JSObject; +using JSC::JSValue; +using JSC::UString; + +using std::min; + +using namespace WTF; + +namespace WebCore { + +using namespace HTMLNames; + +static int s_callingPlugin; + +static String scriptStringIfJavaScriptURL(const KURL& url) +{ + if (!url.protocolIs("javascript")) + 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 defined(ANDROID_PLUGINS) + if (rect != frameRect()) { + Widget::setFrameRect(rect); + setNPWindowRect(rect); // only call when it changes + } +#else + if (rect != frameRect()) + Widget::setFrameRect(rect); +#endif + + updatePluginWidget(); + +#if PLATFORM(WIN_OS) + // On Windows, always call plugin to change geometry. + setNPWindowRect(rect); +#elif XP_UNIX + // On Unix, only call plugin if it's full-page. + if (m_mode == NP_FULL) + setNPWindowRect(rect); +#endif +} + +void PluginView::frameRectsChanged() const +{ + updatePluginWidget(); +} + +void PluginView::handleEvent(Event* event) +{ + if (!m_plugin || m_isWindowed) + return; + + if (event->isMouseEvent()) + handleMouseEvent(static_cast<MouseEvent*>(event)); + else if (event->isKeyboardEvent()) + handleKeyboardEvent(static_cast<KeyboardEvent*>(event)); +} + +bool PluginView::start() +{ + if (m_isStarted) + return false; + + PluginMainThreadScheduler::scheduler().registerPlugin(m_instance); + + ASSERT(m_plugin); + ASSERT(m_plugin->pluginFuncs()->newp); + + NPError npErr; + { + PluginView::setCurrentPluginView(this); + JSC::JSLock::DropAllLocks dropAllLocks(false); + setCallingPlugin(true); + npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.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) + return false; + + m_isStarted = true; + + if (!m_url.isEmpty() && !m_loadManually) { + FrameLoadRequest frameLoadRequest; + frameLoadRequest.resourceRequest().setHTTPMethod("GET"); + frameLoadRequest.resourceRequest().setURL(m_url); + load(frameLoadRequest, false, 0); + } + + return true; +} + +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; +} + +static bool getString(ScriptController* proxy, JSValue* result, String& string) +{ + if (!proxy || !result || result->isUndefined()) + return false; + JSLock lock(false); + + ExecState* exec = proxy->globalObject()->globalExec(); + UString ustring = result->toString(exec); + exec->clearException(); + + string = ustring; + return true; +} + +void PluginView::performRequest(PluginRequest* request) +{ + // 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, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks()); + m_streams.add(stream); + stream->start(); + } else { + m_parentFrame->loader()->load(request->frameLoadRequest().resourceRequest(), targetFrameName); + + // FIXME: <rdar://problem/4807469> This should be sent when the document has finished loading + if (request->sendNotification()) { + PluginView::setCurrentPluginView(this); + JSC::JSLock::DropAllLocks dropAllLocks(false); + 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; + JSValue* result = m_parentFrame->loader()->executeScript(jsString, request->shouldAllowPopups()); + + if (targetFrameName.isNull()) { + String resultString; + + CString cstr; + if (getString(parentFrame->script(), result, resultString)) + cstr = resultString.utf8(); + + RefPtr<PluginStream> stream = PluginStream::create(this, m_parentFrame, 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. + if (m_parentFrame->loader()->documentLoader()->isStopping()) + return NPERR_GENERIC_ERROR; + + const String& targetFrameName = frameLoadRequest.frameName(); + String jsString = scriptStringIfJavaScriptURL(url); + + if (!jsString.isNull()) { + Settings* settings = m_parentFrame->settings(); + + // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does. + if (!settings || !settings->isJavaScriptEnabled()) + 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 (!FrameLoader::canLoad(url, String(), m_parentFrame->document())) { + 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; + + frameLoadRequest.setFrameName(target); + frameLoadRequest.resourceRequest().setHTTPMethod("GET"); + frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url)); + + return load(frameLoadRequest, true, notifyData); +} + +NPError PluginView::getURL(const char* url, const char* target) +{ + FrameLoadRequest frameLoadRequest; + + frameLoadRequest.setFrameName(target); + frameLoadRequest.resourceRequest().setHTTPMethod("GET"); + frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url)); + + return load(frameLoadRequest, false, 0); +} + +NPError PluginView::postURLNotify(const char* url, const char* target, uint32 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 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 PluginView::write(NPStream* stream, int32 len, void* buffer) +{ + notImplemented(); + // Unsupported + return -1; +} + +NPError PluginView::destroyStream(NPStream* stream, NPReason reason) +{ + PluginStream* browserStream = static_cast<PluginStream*>(stream->ndata); + + if (!stream || PluginStream::ownerForStream(stream) != m_instance) + return NPERR_INVALID_INSTANCE_ERROR; + + browserStream->cancelAndDestroyStream(reason); + return NPERR_NO_ERROR; +} + +void PluginView::status(const char* message) +{ + if (Page* page = m_parentFrame->page()) + page->chrome()->setStatusbarText(m_parentFrame, String(message)); +} + +NPError PluginView::setValue(NPPVariable variable, void* value) +{ + switch (variable) { + case NPPVpluginWindowBool: + m_isWindowed = value; + return NPERR_NO_ERROR; + case NPPVpluginTransparentBool: + m_isTransparent = value; + return NPERR_NO_ERROR; + default: +#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); +} + +PassRefPtr<JSC::Bindings::Instance> PluginView::bindingInstance() +{ +#if ENABLE(NETSCAPE_PLUGIN_API) + NPObject* object = 0; + + if (!m_plugin || !m_plugin->pluginFuncs()->getvalue) + return 0; + + NPError npErr; + { + PluginView::setCurrentPluginView(this); + JSC::JSLock::DropAllLocks dropAllLocks(false); + setCallingPlugin(true); + npErr = m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginScriptableNPObject, &object); + setCallingPlugin(false); + PluginView::setCurrentPluginView(0); + } + + if (npErr != NPERR_NO_ERROR || !object) + 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 +} + +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; + + 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_paramNames(0) + , m_paramValues(0) + , m_isWindowed(true) + , m_isTransparent(false) + , m_haveInitialized(false) +#if PLATFORM(GTK) || defined(Q_WS_X11) + , m_needsXEmbed(false) +#endif +#if PLATFORM(QT) + , m_isNPAPIPlugin(false) +#endif +#if PLATFORM(WIN_OS) && !PLATFORM(WX) && ENABLE(NETSCAPE_PLUGIN_API) + , m_pluginWndProc(0) + , m_lastMessage(0) + , m_isCallingPluginWndProc(false) +#endif +#if PLATFORM(WIN_OS) && PLATFORM(QT) + , m_window(0) +#endif + , m_loadManually(loadManually) + , m_manualStream(0) + , m_isJavaScriptPaused(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; + + m_mimeType = mimeType.utf8(); + + setParameters(paramNames, paramValues); + +#ifdef XP_UNIX + m_npWindow.ws_info = 0; +#endif + + m_mode = m_loadManually ? NP_FULL : NP_EMBED; + + resize(size); +} + +void PluginView::didReceiveResponse(const ResourceResponse& response) +{ + ASSERT(m_loadManually); + ASSERT(!m_manualStream); + + m_manualStream = PluginStream::create(this, m_parentFrame, 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) +{ + ASSERT(m_loadManually); + ASSERT(m_manualStream); + + m_manualStream->didReceiveData(0, data, length); +} + +void PluginView::didFinishLoading() +{ + ASSERT(m_loadManually); + ASSERT(m_manualStream); + + m_manualStream->didFinishLoading(0); +} + +void PluginView::didFail(const ResourceError& error) +{ + 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; +} + +PluginView* PluginView::create(Frame* parentFrame, const IntSize& size, Element* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually) +{ + // if we fail to find a plugin for this MIME type, findPlugin will search for + // a plugin by the file extension and update the MIME type, so pass a mutable String + String mimeTypeCopy = mimeType; + PluginPackage* plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy); + + // No plugin was found, try refreshing the database and searching again + if (!plugin && PluginDatabase::installedPlugins()->refresh()) { + mimeTypeCopy = mimeType; + plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy); + } + + return new PluginView(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually); +} + +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 len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders) +{ + if (!url || !len || !buf) + return NPERR_INVALID_PARAM; + + FrameLoadRequest frameLoadRequest; + + 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 PluginView::scheduleTimer(NPP instance, uint32 interval, bool repeat, + void (*timerFunc)(NPP, uint32 timerID)) +{ + return m_timerList.schedule(instance, interval, repeat, timerFunc); +} + +void PluginView::unscheduleTimer(NPP instance, uint32 timerID) +{ + m_timerList.unschedule(instance, timerID); +} +#endif + +void PluginView::invalidateWindowlessPluginRect(const IntRect& rect) +{ + if (!isVisible()) + return; + + RenderObject* renderer = m_element->renderer(); + if (!renderer) + return; + + IntRect dirtyRect = rect; + dirtyRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop()); + renderer->repaintRectangle(dirtyRect); +} + +} // namespace WebCore diff --git a/WebCore/plugins/PluginView.h b/WebCore/plugins/PluginView.h index 9256256..1a189e8 100644 --- a/WebCore/plugins/PluginView.h +++ b/WebCore/plugins/PluginView.h @@ -1,6 +1,7 @@ + /* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,36 +28,37 @@ #ifndef PluginView_H #define PluginView_H -#ifdef ANDROID_PLUGINS - -#include "PluginViewAndroid.h" - -namespace WebCore { - typedef PluginViewAndroid PluginView; -} - -#else // !defined(ANDROID_PLUGINS) - -#include <winsock2.h> -#include <windows.h> - #include "CString.h" +#include "FrameLoadRequest.h" #include "IntRect.h" #include "KURL.h" #include "PlatformString.h" #include "PluginStream.h" -#include "PluginQuirkSet.h" #include "ResourceRequest.h" #include "Timer.h" #include "Widget.h" -#include "npapi.h" +#include "npruntime_internal.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> -namespace KJS { +#ifdef PLUGIN_SCHEDULE_TIMER +#include "PluginTimer.h" +#endif + +#if PLATFORM(WIN_OS) && PLATFORM(QT) +typedef struct HWND__* HWND; +typedef HWND PlatformPluginWidget; +#elif defined(ANDROID_PLUGINS) +typedef struct PluginWidgetAndroid* PlatformPluginWidget; +#else +typedef PlatformWidget PlatformPluginWidget; +#endif + +namespace JSC { namespace Bindings { class Instance; } @@ -65,11 +67,12 @@ namespace KJS { namespace WebCore { class Element; class Frame; - struct FrameLoadRequest; class KeyboardEvent; class MouseEvent; class KURL; +#if PLATFORM(WIN_OS) && !PLATFORM(WX) && ENABLE(NETSCAPE_PLUGIN_API) class PluginMessageThrottlerWin; +#endif class PluginPackage; class PluginRequest; class PluginStream; @@ -82,11 +85,28 @@ namespace WebCore { PluginStatusLoadedSuccessfully }; - class PluginView : public Widget, private PluginStreamClient { - friend static LRESULT CALLBACK PluginViewWndProc(HWND, UINT, WPARAM, LPARAM); + class PluginRequest { + 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 PluginView : public Widget, private PluginStreamClient { public: - PluginView(Frame* parentFrame, const IntSize&, PluginPackage* plugin, Element*, const KURL&, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually); + static 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(); } @@ -95,7 +115,7 @@ namespace WebCore { void setNPWindowRect(const IntRect&); static PluginView* currentPluginView(); - KJS::Bindings::Instance* bindingInstance(); + PassRefPtr<JSC::Bindings::Instance> bindingInstance(); PluginStatus status() const { return m_status; } @@ -108,36 +128,59 @@ namespace WebCore { int32 write(NPStream* stream, int32 len, void* buffer); NPError destroyStream(NPStream* stream, NPReason reason); const char* userAgent(); +#if ENABLE(NETSCAPE_PLUGIN_API) + static const char* userAgentStatic(); +#endif void status(const char* message); NPError getValue(NPNVariable variable, void* value); +#if ENABLE(NETSCAPE_PLUGIN_API) + static NPError getValueStatic(NPNVariable variable, void* value); +#endif NPError setValue(NPPVariable variable, void* value); void invalidateRect(NPRect*); void invalidateRegion(NPRegion); void forceRedraw(); void pushPopupsEnabledState(bool state); void popPopupsEnabledState(); +#ifdef PLUGIN_SCHEDULE_TIMER + uint32 scheduleTimer(NPP, uint32 interval, bool repeat, + void (*timerFunc)(NPP, uint32 timerID)); + void unscheduleTimer(NPP, uint32 timerID); +#endif + + virtual void invalidateRect(const IntRect&); bool arePopupsAllowed() const; + void setJavaScriptPaused(bool); + void disconnectStream(PluginStream*); void streamDidFinishLoading(PluginStream* stream) { disconnectStream(stream); } // Widget functions - virtual void setFrameGeometry(const IntRect&); - virtual void geometryChanged() const; + virtual void setFrameRect(const IntRect&); + virtual void frameRectsChanged() const; virtual void setFocus(); virtual void show(); virtual void hide(); virtual void paint(GraphicsContext*, const IntRect&); - virtual IntRect windowClipRect() const; + + // 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 void attachToWindow(); - virtual void detachFromWindow(); + virtual bool isPluginView() const { return true; } +#if PLATFORM(WIN_OS) && !PLATFORM(WX) && 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&); @@ -147,7 +190,14 @@ namespace WebCore { static bool isCallingPlugin(); +#if PLATFORM(QT) + bool isNPAPIPlugin() const { return m_isNPAPIPlugin; } + void setIsNPAPIPlugin(bool b) { m_isNPAPIPlugin = b; } +#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); void init(); bool start(); @@ -155,10 +205,15 @@ namespace WebCore { static void setCurrentPluginView(PluginView*); NPError load(const FrameLoadRequest&, bool sendNotification, void* notifyData); NPError handlePost(const char* url, const char* target, uint32 len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders); + NPError handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf); + static void freeStringArray(char** stringArray, int length); void setCallingPlugin(bool) const; + + void invalidateWindowlessPluginRect(const IntRect&); + + Frame* m_parentFrame; RefPtr<PluginPackage> m_plugin; Element* m_element; - Frame* m_parentFrame; bool m_isStarted; KURL m_url; KURL m_baseURL; @@ -175,16 +230,24 @@ namespace WebCore { void popPopupsStateTimerFired(Timer<PluginView>*); Timer<PluginView> m_popPopupsStateTimer; +#ifndef NP_NO_CARBON bool dispatchNPEvent(NPEvent&); - OwnPtr<PluginMessageThrottlerWin> m_messageThrottler; - - void updateWindow() const; - void determineQuirks(const String& mimeType); +#endif + void updatePluginWidget() const; void paintMissingPluginIcon(GraphicsContext*, const IntRect&); void handleKeyboardEvent(KeyboardEvent*); void handleMouseEvent(MouseEvent*); +#ifdef ANDROID_PLUGINS + // 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; @@ -196,35 +259,62 @@ namespace WebCore { NPP m_instance; NPP_t m_instanceStruct; NPWindow m_npWindow; - + Vector<bool, 4> m_popupStateStack; HashSet<RefPtr<PluginStream> > m_streams; Vector<PluginRequest*> m_requests; - PluginQuirkSet m_quirks; bool m_isWindowed; bool m_isTransparent; - bool m_isVisible; - bool m_attachedToWindow; bool m_haveInitialized; - WNDPROC m_pluginWndProc; - HWND m_window; // for windowed plug-ins - mutable IntRect m_clipRect; // The clip rect to apply to a windowed plug-in - mutable IntRect m_windowRect; // Our window rect. +#if PLATFORM(QT) + bool m_isNPAPIPlugin; +#endif +#if PLATFORM(GTK) || defined(Q_WS_X11) + bool m_needsXEmbed; +#endif + +#if PLATFORM(WIN_OS) && !PLATFORM(WX) && ENABLE(NETSCAPE_PLUGIN_API) + OwnPtr<PluginMessageThrottlerWin> m_messageThrottler; + WNDPROC m_pluginWndProc; unsigned m_lastMessage; bool m_isCallingPluginWndProc; +#endif + +#ifdef PLUGIN_SCHEDULE_TIMER + PluginTimerList m_timerList; +#endif + +#if PLATFORM(WIN_OS) && PLATFORM(QT) + // Only under Qt on Windows, the plugin widget (HWND) does not match the native widget (QWidget). + PlatformPluginWidget m_window; // for windowed plug-ins +public: + PlatformPluginWidget platformPluginWidget() const { return m_window; } +#elif defined(ANDROID_PLUGINS) +public: + PlatformPluginWidget m_window; + PlatformPluginWidget platformPluginWidget() const { return m_window; } // MANUAL MERGE FIXME +#else +public: + PlatformPluginWidget platformPluginWidget() const { return platformWidget(); } +#endif + +private: + + mutable IntRect m_clipRect; // The clip rect to apply to a windowed plug-in + mutable IntRect m_windowRect; // Our window rect. bool m_loadManually; RefPtr<PluginStream> m_manualStream; + bool m_isJavaScriptPaused; + static PluginView* s_currentPluginView; }; } // namespace WebCore -#endif // !defined(ANDROID_PLUGINS) - #endif diff --git a/WebCore/plugins/android/PlugInInfoStoreAndroid.cpp b/WebCore/plugins/android/PlugInInfoStoreAndroid.cpp deleted file mode 100644 index 780e5f0..0000000 --- a/WebCore/plugins/android/PlugInInfoStoreAndroid.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "PluginInfoStore.h" -#include "PluginDatabaseAndroid.h" -#include "PluginPackageAndroid.h" - -namespace WebCore { - -PluginInfo* PluginInfoStore::createPluginInfoForPluginAtIndex(unsigned i) -{ - PluginDatabaseAndroid *db = PluginDatabaseAndroid::installedPlugins(); - PluginInfo* info = new PluginInfo; - PluginPackageAndroid* package = db->plugins()[i]; - - info->name = package->name(); - info->file = package->fileName(); - info->desc = package->description(); - - const MIMEToDescriptionsMap& mimeToDescriptions = package->mimeToDescriptions(); - MIMEToDescriptionsMap::const_iterator end = mimeToDescriptions.end(); - for (MIMEToDescriptionsMap::const_iterator it = mimeToDescriptions.begin(); it != end; ++it) { - MimeClassInfo* mime = new MimeClassInfo; - info->mimes.append(mime); - - mime->type = it->first; - mime->desc = it->second; - mime->plugin = info; - - Vector<String> extensions = package->mimeToExtensions().get(mime->type); - - for (unsigned i = 0; i < extensions.size(); i++) { - if (i > 0) - mime->suffixes += ","; - - mime->suffixes += extensions[i]; - } - } - - return info; -} - -unsigned PluginInfoStore::pluginCount() const -{ - return PluginDatabaseAndroid::installedPlugins()->plugins().size(); -} - -bool PluginInfoStore::supportsMIMEType(const WebCore::String& mimeType) -{ - return PluginDatabaseAndroid::installedPlugins()->isMIMETypeRegistered(mimeType); -} - -void refreshPlugins(bool reloadOpenPages) -{ - PluginDatabaseAndroid::installedPlugins()->refresh(); - - if (reloadOpenPages) { - // FIXME: reload open pages - } -} - -} diff --git a/WebCore/plugins/android/PluginDatabaseAndroid.cpp b/WebCore/plugins/android/PluginDatabaseAndroid.cpp deleted file mode 100644 index 411855c..0000000 --- a/WebCore/plugins/android/PluginDatabaseAndroid.cpp +++ /dev/null @@ -1,347 +0,0 @@ -#ifdef ANDROID_PLUGINS - -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "PluginDatabaseAndroid.h" -#include "PluginPackageAndroid.h" -#include "PluginViewAndroid.h" -#include "Frame.h" -#include <sys/types.h> -#include <dirent.h> -#include <limits.h> -#include <stdlib.h> - -#include "PluginDebug.h" - -namespace WebCore { - -String PluginDatabaseAndroid::s_defaultPluginsPath; - -PluginDatabaseAndroid* PluginDatabaseAndroid::installedPlugins() -{ - static PluginDatabaseAndroid* plugins = 0; - - if (!plugins) { - plugins = new PluginDatabaseAndroid; - plugins->refresh(); - } - - return plugins; -} - -void PluginDatabaseAndroid::setDefaultPluginsPath(const String& path) -{ - // Change the default plugins path and rescan. - if(path != s_defaultPluginsPath) { - s_defaultPluginsPath = path; - installedPlugins()->refresh(); - } -} - -PluginDatabaseAndroid::PluginDatabaseAndroid() - : m_pluginsPaths() - , m_plugins() -{ -} - -PluginDatabaseAndroid::~PluginDatabaseAndroid() -{ -} - -void PluginDatabaseAndroid::addExtraPluginPath(const String& path) -{ - m_pluginsPaths.append(path); - refresh(); -} - -bool PluginDatabaseAndroid::addPluginFile(const String& path) -{ - PLUGIN_LOG("Adding plugin \"%s\"\n", path.utf8().data()); - - // Check if the plugin is already loaded. - PluginPackageAndroid* plugin = findPluginByPath(path); - - // Stat the file to check we can access it. - struct stat statbuf; - if(stat(path.utf8().data(), &statbuf)) { - // Stat failed. We can't access this file. - PLUGIN_LOG("Couldn't stat library \"%s\": %s\n", - path.utf8().data(), strerror(errno)); - // Well, can't load this plugin, then. - if(plugin) { - // If we previous succeeded loading it, unload it now. - removePlugin(plugin); - } - // Failed to load. - return false; - } - - // Check the modification time. - uint32 lastModified = statbuf.st_mtime; - if(plugin) { - // Compare to the currently loaded version. - if(lastModified == plugin->getLastModified()) { - // It's the same plugin. No new actions required. - return true; - } else { - // It has been modified. Unload the old version. - removePlugin(plugin); - } - } - - // If we get here, we either just unloaded an old plugin, or this - // is a new one. Create a new package. - PluginPackageAndroid* package = - PluginPackageAndroid::createPackage(path, lastModified); - if(package) { - // Success, add to the vector of plugins. - PLUGIN_LOG("Successfully added plugin \"%s\"\n", path.utf8().data()); - m_plugins.append(package); - return true; - } else { - // Failed. - return false; - } -} - -bool PluginDatabaseAndroid::addPluginsInDirectory(const String& path) -{ - // Open a directory iterator - DIR* dir_it = opendir(path.utf8().data()); - if(!dir_it) { - PLUGIN_LOG("Cannot open directory \"%s\"\n", - path.utf8().data()); - return false; - } - // Scan the directory for "*.so" and "*.so.*" files. - struct dirent* entry; - while((entry = readdir(dir_it)) != NULL) { - const char* name = entry->d_name; - // Skip current and parent directory entries. - if(!strcmp(name, ".") || !strcmp(name, "..")) - continue; - const char* so = strstr(name, ".so"); - if(so && (so[3] == 0 || so[3] == '.')) { - // Matches our pattern, add it. - addPluginFile(path + "/" + name); - } - } - closedir(dir_it); - return true; -} - -void PluginDatabaseAndroid::removePlugin(PluginPackageAndroid* plugin) -{ - // Find this plugin in the array and remove it. - for(unsigned i = 0; i < m_plugins.size(); ++i) { - if(m_plugins[i] == plugin) { - PLUGIN_LOG("Removed plugin \"%s\"\n", - plugin->path().utf8().data()); - // This will cause a reference count to decrement. When - // the plugin actually stops getting used by all - // documents, its instance will delete itself. - m_plugins.remove(i); - break; - } - } - PLUGIN_LOG("Tried to remove plugin %p which didn't exist!\n", plugin); -} - -bool PluginDatabaseAndroid::refresh() -{ - PLUGIN_LOG("PluginDatabaseAndroid::refresh()\n"); - - // Don't delete existing plugins. The directory scan will add new - // plugins and also refresh old plugins if their file is modified - // since the last check. - - // Scan each directory and add any plugins found in them. This is - // not recursive. - if(s_defaultPluginsPath.length() > 0) - addPluginsInDirectory(s_defaultPluginsPath); - for(unsigned i = 0; i < m_pluginsPaths.size(); ++i) - addPluginsInDirectory(m_pluginsPaths[i]); - - // Now stat() all plugins and remove any that we can't - // access. This handles the case of a plugin being deleted at - // runtime. - for(unsigned i = 0; i < m_plugins.size();) { - struct stat statbuf; - if(stat(m_plugins[i]->path().utf8().data(), &statbuf)) { - // It's gone away. Remove it from the list. - m_plugins.remove(i); - } else { - ++i; - } - } - - return true; -} - -Vector<PluginPackageAndroid*> PluginDatabaseAndroid::plugins() const -{ - Vector<PluginPackageAndroid*> result; - - for(PackageRefVector::const_iterator it = m_plugins.begin(); - it != m_plugins.end(); ++it) - result.append(it->get()); - - return result; -} - -bool PluginDatabaseAndroid::isMIMETypeRegistered(const String& mimeType) const -{ - // Iterate through every package - for(PackageRefVector::const_iterator it = m_plugins.begin(); - it != m_plugins.end(); ++it) { - // Check if this package has the MIME type mapped to an extension - const PluginPackageAndroid *package = it->get(); - const MIMEToExtensionsMap& mime_extension_map = - package->mimeToExtensions(); - if(mime_extension_map.find(mimeType) != mime_extension_map.end()) { - // Found it - return true; - } - } - // No package has this MIME type - return false; -} - -bool PluginDatabaseAndroid::isPluginBlacklisted(PluginPackageAndroid* plugin) -{ - // If there is ever a plugin in the wild which causes the latest - // version of Android to crash, then stick a check here for it and - // return true when matched. - return false; -} - -PluginPackageAndroid* PluginDatabaseAndroid::pluginForMIMEType( - const String& mimeType) -{ - // Todo: these data structures are not right. This is inefficient. - // Iterate through every package - for(PackageRefVector::iterator it = m_plugins.begin(); - it != m_plugins.end(); ++it) { - // Check if this package has the MIME type mapped to a description - PluginPackageAndroid *package = it->get(); - const MIMEToDescriptionsMap& mime_desc_map = - package->mimeToDescriptions(); - if(mime_desc_map.find(mimeType) != mime_desc_map.end()) { - // Found it - return package; - } - } - // No package has this MIME type - return NULL; -} - -String PluginDatabaseAndroid::MIMETypeForExtension(const String& extension) - const -{ - // Todo: these data structures are not right. This is inefficient. - // Iterate through every package - for(PackageRefVector::const_iterator it = m_plugins.begin(); - it != m_plugins.end(); ++it) { - // Check if this package has the MIME type mapped to an extension - PluginPackageAndroid *package = it->get(); - const MIMEToDescriptionsMap& mime_desc_map = - package->mimeToDescriptions(); - for(MIMEToDescriptionsMap::const_iterator map_it = - mime_desc_map.begin(); - map_it != mime_desc_map.end(); ++map_it) { - if(map_it->second == extension) { - // Found it - return map_it->first; - } - } - } - // No MIME type matches this extension - return String(""); -} - -PluginPackageAndroid* PluginDatabaseAndroid::findPlugin(const KURL& url, - String& mimeType) -{ - PluginPackageAndroid* plugin = pluginForMIMEType(mimeType); - String filename = url.string(); - - if (!plugin) { - String filename = url.lastPathComponent(); - if (!filename.endsWith("/")) { - int extensionPos = filename.reverseFind('.'); - if (extensionPos != -1) { - String extension = filename.substring(extensionPos + 1); - - mimeType = MIMETypeForExtension(extension); - if (mimeType.length()) { - plugin = pluginForMIMEType(mimeType); - } - } - } - } - // No MIME type matches this url - return plugin; -} - -PluginPackageAndroid* PluginDatabaseAndroid::findPluginByPath( - const String& path) -{ - for(PackageRefVector::iterator it = m_plugins.begin(); - it != m_plugins.end(); ++it) { - if((*it)->path() == path) - return it->get(); // Found it - } - return 0; // Not found. -} - -PluginViewAndroid* PluginDatabaseAndroid::createPluginView( - Frame* parentFrame, - const IntSize& size, - Element* element, - const KURL& url, - const Vector<String>& paramNames, - const Vector<String>& paramValues, - const String& mimeType, - bool loadManually) -{ - // if we fail to find a plugin for this MIME type, findPlugin will search for - // a plugin by the file extension and update the MIME type, so pass a mutable String - String mimeTypeCopy = mimeType; - PluginPackageAndroid* plugin = findPlugin(url, mimeTypeCopy); - - // No plugin was found, try refreshing the database and searching again - if (!plugin && refresh()) { - mimeTypeCopy = mimeType; - plugin = findPlugin(url, mimeTypeCopy); - } - - return new PluginViewAndroid(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually); -} - -} - -#endif diff --git a/WebCore/plugins/android/PluginDatabaseAndroid.h b/WebCore/plugins/android/PluginDatabaseAndroid.h deleted file mode 100644 index 72814e9..0000000 --- a/WebCore/plugins/android/PluginDatabaseAndroid.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifdef ANDROID_PLUGINS - -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PluginDatabaseAndroid_H -#define PluginDatabaseAndroid_H - -#include <wtf/Vector.h> - -#include "PlatformString.h" -#include "PluginPackageAndroid.h" - -namespace WebCore { - class Element; - class Frame; - class IntSize; - class KURL; - class PluginPackageAndroid; - class PluginViewAndroid; - - class PluginDatabaseAndroid { - public: - ~PluginDatabaseAndroid(); - - static PluginDatabaseAndroid* installedPlugins(); - PluginViewAndroid* createPluginView(Frame* parentFrame, - const IntSize&, - Element* element, - const KURL& url, - const Vector<String>& paramNames, - const Vector<String>& paramValues, - const String& mimeType, - bool loadManually); - - bool refresh(); - Vector<PluginPackageAndroid*> plugins() const; - bool isMIMETypeRegistered(const String& mimeType) const; - void addExtraPluginPath(const String&); - static bool isPluginBlacklisted(PluginPackageAndroid* plugin); - static void setDefaultPluginsPath(const String&); - - private: - explicit PluginDatabaseAndroid(); - - bool addPluginFile(const String& path); - bool addPluginsInDirectory(const String& path); - PluginPackageAndroid* findPlugin(const KURL& url, String& mimeType); - PluginPackageAndroid* pluginForMIMEType(const String& mimeType); - String MIMETypeForExtension(const String& extension) const; - PluginPackageAndroid* findPluginByPath(const String& path); - void removePlugin(PluginPackageAndroid* plugin); - - // List of all paths to search for plugins - Vector<String> m_pluginsPaths; - - // List of all PluginPackageAndroid instances - typedef Vector<RefPtr<PluginPackageAndroid> > PackageRefVector; - PackageRefVector m_plugins; - - // The default plugins path from Settings. - static String s_defaultPluginsPath; - }; - -} // namespace WebCore - -#endif - -#endif diff --git a/WebCore/plugins/android/PluginDebug.h b/WebCore/plugins/android/PluginDebug.h deleted file mode 100644 index 8adbbd7..0000000 --- a/WebCore/plugins/android/PluginDebug.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifdef ANDROID_PLUGINS - -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#ifndef PLUGIN_DEBUG_H__ -#define PLUGIN_DEBUG_H__ - -// Include this file last to avoid clashes with the definition of LOG. - -#undef LOG -#define LOG_TAG "WebKit" -#include "utils/Log.h" - -// Define PLUGIN_DEBUG_LOCAL in an individual C++ file to enable for -// that file only. - -// Define PLUGIN_DEBUG_GLOBAL to 1 to turn plug-in debug for all -// Android plug-in code in this direectory. -#define PLUGIN_DEBUG_GLOBAL 0 - -#if PLUGIN_DEBUG_GLOBAL || defined(PLUGIN_DEBUG_LOCAL) -# define PLUGIN_LOG(A, B...) do { LOGI( A , ## B ); } while(0) -#else -# define PLUGIN_LOG(A, B...) do { } while(0) -#endif - -#endif // defined(PLUGIN_DEBUG_H__) - -#endif // defined(ANDROID_PLUGINS) diff --git a/WebCore/plugins/android/PluginPackageAndroid.cpp b/WebCore/plugins/android/PluginPackageAndroid.cpp deleted file mode 100644 index b8dca9a..0000000 --- a/WebCore/plugins/android/PluginPackageAndroid.cpp +++ /dev/null @@ -1,504 +0,0 @@ -#ifdef ANDROID_PLUGINS - -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "WebCoreJni.h" -#include "PluginPackageAndroid.h" -#include "PluginDatabaseAndroid.h" - -#include "Timer.h" -#include "DeprecatedString.h" -#include "PlatformString.h" -#include "CString.h" -#include "npruntime_impl.h" - -#include <dlfcn.h> -#include <errno.h> - -#include "PluginDebug.h" - -namespace WebCore { - -PluginPackageAndroid::PluginPackageAndroid(const String& path, - uint32 lastModified) - : m_path(path), - m_name(), - m_fileName(), - m_description(), - m_lastModified(lastModified), - m_pluginFuncs(), - m_mimeToDescriptions(), - m_mimeToExtensions(), - m_env(0), - m_pluginObject(0), - m_libraryHandle(NULL), - m_libraryInitialized(false), - m_NP_Initialize((NP_InitializeFuncPtr) NULL), - m_NP_Shutdown((NP_ShutdownFuncPtr) NULL), - m_NP_GetMIMEDescription((NP_GetMIMEDescriptionFuncPtr) NULL), - m_NP_GetValue((NP_GetValueFuncPtr) NULL) -{ - PLUGIN_LOG("Constructing PluginPackageAndroid\n"); - if(android::WebCoreJni::getJavaVM()->GetEnv((void**) &m_env, - JNI_VERSION_1_4) != JNI_OK) { - PLUGIN_LOG("GetEnv failed!"); - } -} - -PluginPackageAndroid::~PluginPackageAndroid() -{ - PLUGIN_LOG("Destructing PluginPackageAndroid\n"); - unload(); -} - -void PluginPackageAndroid::initializeBrowserFuncs() -{ - // Initialize the NPN function pointers that we hand over to the - // plugin. - - memset(&m_browserFuncs, 0, sizeof(m_browserFuncs)); - - m_browserFuncs.size = sizeof(m_browserFuncs); - m_browserFuncs.version = NP_VERSION_MINOR; - m_browserFuncs.geturl = NPN_GetURL; - m_browserFuncs.posturl = NPN_PostURL; - m_browserFuncs.requestread = NPN_RequestRead; - m_browserFuncs.newstream = NPN_NewStream; - m_browserFuncs.write = NPN_Write; - m_browserFuncs.destroystream = NPN_DestroyStream; - m_browserFuncs.status = NPN_Status; - m_browserFuncs.uagent = NPN_UserAgent; - m_browserFuncs.memalloc = NPN_MemAlloc; - m_browserFuncs.memfree = NPN_MemFree; - m_browserFuncs.memflush = NPN_MemFlush; - m_browserFuncs.reloadplugins = NPN_ReloadPlugins; - m_browserFuncs.geturlnotify = NPN_GetURLNotify; - m_browserFuncs.posturlnotify = NPN_PostURLNotify; - m_browserFuncs.getvalue = NPN_GetValue; - m_browserFuncs.setvalue = NPN_SetValue; - m_browserFuncs.invalidaterect = NPN_InvalidateRect; - m_browserFuncs.invalidateregion = NPN_InvalidateRegion; - m_browserFuncs.forceredraw = NPN_ForceRedraw; - m_browserFuncs.getJavaEnv = NPN_GetJavaEnv; - m_browserFuncs.getJavaPeer = NPN_GetJavaPeer; - m_browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState; - m_browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState; - m_browserFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall; - - m_browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue; - m_browserFuncs.getstringidentifier = _NPN_GetStringIdentifier; - m_browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers; - m_browserFuncs.getintidentifier = _NPN_GetIntIdentifier; - m_browserFuncs.identifierisstring = _NPN_IdentifierIsString; - m_browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier; - m_browserFuncs.intfromidentifier = _NPN_IntFromIdentifier; - m_browserFuncs.createobject = _NPN_CreateObject; - m_browserFuncs.retainobject = _NPN_RetainObject; - m_browserFuncs.releaseobject = _NPN_ReleaseObject; - m_browserFuncs.invoke = _NPN_Invoke; - m_browserFuncs.invokeDefault = _NPN_InvokeDefault; - m_browserFuncs.evaluate = _NPN_Evaluate; - m_browserFuncs.getproperty = _NPN_GetProperty; - m_browserFuncs.setproperty = _NPN_SetProperty; - m_browserFuncs.removeproperty = _NPN_RemoveProperty; - m_browserFuncs.hasproperty = _NPN_HasProperty; - m_browserFuncs.hasmethod = _NPN_HasMethod; - m_browserFuncs.setexception = _NPN_SetException; - m_browserFuncs.enumerate = _NPN_Enumerate; -} - -jobject PluginPackageAndroid::createPluginObject(const char *name, - const char *path, - const char *fileName, - const char *description) -{ - // Create a Java "class Plugin" object instance - jclass pluginClass = m_env->FindClass("android/webkit/Plugin"); - if(!pluginClass) { - PLUGIN_LOG("Couldn't find class android.webkit.Plugin\n"); - return 0; - } - // Get Plugin(String, String, String, String, Context) - jmethodID pluginConstructor = m_env->GetMethodID( - pluginClass, - "<init>", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - if(!pluginConstructor) { - PLUGIN_LOG("Couldn't get android.webkit.Plugin constructor\n"); - return 0; - } - // Make Java strings of name, path, fileName, description - jstring javaName = m_env->NewStringUTF(name); - jstring javaPath = m_env->NewStringUTF(m_path.utf8().data()); - jstring javaFileName = m_env->NewStringUTF(m_fileName.utf8().data()); - jstring javaDescription = m_env->NewStringUTF(description); - // Make a plugin instance - jobject pluginObject = m_env->NewObject(pluginClass, - pluginConstructor, - javaName, - javaPath, - javaFileName, - javaDescription); - return pluginObject; -} - -jobject PluginPackageAndroid::getPluginListObject() -{ - // Get WebView.getPluginList() - jclass webViewClass = m_env->FindClass("android/webkit/WebView"); - if(!webViewClass) { - PLUGIN_LOG("Couldn't find class android.webkit.WebView\n"); - return 0; - } - jmethodID getPluginList = m_env->GetStaticMethodID( - webViewClass, - "getPluginList", - "()Landroid/webkit/PluginList;"); - if(!getPluginList) { - PLUGIN_LOG("Couldn't find android.webkit.WebView.getPluginList()\n"); - return 0; - } - // Get the PluginList instance - jobject pluginListObject = m_env->CallStaticObjectMethod(webViewClass, - getPluginList); - if(!pluginListObject) { - PLUGIN_LOG("Couldn't get PluginList object\n"); - return 0; - } - return pluginListObject; -} - -bool PluginPackageAndroid::addPluginObjectToList(jobject pluginList, - jobject plugin) -{ - // Add the Plugin object - jclass pluginListClass = m_env->FindClass("android/webkit/PluginList"); - if(!pluginListClass) { - PLUGIN_LOG("Couldn't find class android.webkit.PluginList\n"); - return false; - } - jmethodID addPlugin = m_env->GetMethodID( - pluginListClass, - "addPlugin", - "(Landroid/webkit/Plugin;)V"); - if(!addPlugin) { - PLUGIN_LOG("Couldn't find android.webkit.PluginList.addPlugin()\n"); - return false; - } - m_env->CallVoidMethod(pluginList, - addPlugin, - plugin); - return true; -} - -void PluginPackageAndroid::removePluginObjectFromList(jobject pluginList, - jobject plugin) -{ - // Remove the Plugin object - jclass pluginListClass = m_env->FindClass("android/webkit/PluginList"); - if(!pluginListClass) { - PLUGIN_LOG("Couldn't find class android.webkit.PluginList\n"); - return; - } - jmethodID removePlugin = m_env->GetMethodID( - pluginListClass, - "removePlugin", - "(Landroid/webkit/Plugin;)V"); - if(!removePlugin) { - PLUGIN_LOG("Couldn't find android.webkit.PluginList.removePlugin()\n"); - return; - } - m_env->CallVoidMethod(pluginList, - removePlugin, - plugin); -} - -bool PluginPackageAndroid::load() -{ - if(m_libraryHandle) { - PLUGIN_LOG("Plugin \"%s\" already loaded\n", m_path.utf8().data()); - return true; - } - - PLUGIN_LOG("Loading \"%s\"\n", m_path.utf8().data()); - - // Open the library - void *handle = dlopen(m_path.utf8().data(), RTLD_NOW); - if(!handle) { - PLUGIN_LOG("Couldn't load plugin library \"%s\": %s\n", - m_path.utf8().data(), dlerror()); - return false; - } - m_libraryHandle = handle; - // This object will call dlclose() and set m_libraryHandle to NULL - // when going out of scope. - DynamicLibraryCloser dlCloser(this); - - // Get the four entry points we need for Linux Netscape Plug-ins - if(!getEntryPoint("NP_Initialize", (void **) &m_NP_Initialize) || - !getEntryPoint("NP_Shutdown", (void **) &m_NP_Shutdown) || - !getEntryPoint("NP_GetMIMEDescription", - (void **) &m_NP_GetMIMEDescription) || - !getEntryPoint("NP_GetValue", (void **) &m_NP_GetValue)) { - // If any of those failed to resolve, fail the entire load - return false; - } - - // Get the plugin name and description using NP_GetValue - const char *name; - const char *description; - if(m_NP_GetValue(NULL, NPPVpluginNameString, - &name) != NPERR_NO_ERROR || - m_NP_GetValue(NULL, NPPVpluginDescriptionString, - &description) != NPERR_NO_ERROR) { - PLUGIN_LOG("Couldn't get name/description using NP_GetValue\n"); - return false; - } - - PLUGIN_LOG("Plugin name: \"%s\"\n", name); - PLUGIN_LOG("Plugin description: \"%s\"\n", description); - m_name = name; - m_description = description; - - // fileName is just the trailing part of the path - int last_slash = m_path.reverseFind('/'); - if(last_slash < 0) - m_fileName = m_path; - else - m_fileName = m_path.substring(last_slash + 1); - - // Grab the MIME description. This is in the format, e.g: - // application/x-somescriptformat:ssf:Some Script Format - const char *mime_description = m_NP_GetMIMEDescription(); - if(!initializeMIMEDescription(mime_description)) { - PLUGIN_LOG("Bad MIME description: \"%s\"\n", - mime_description); - return false; - } - - // Create a new Java Plugin object. - jobject pluginObject = createPluginObject(name, - m_path.utf8().data(), - m_fileName.utf8().data(), - description); - if(!pluginObject) { - PLUGIN_LOG("Couldn't create Java Plugin\n"); - return false; - } - - // Provide the plugin with our browser function table and grab its - // plugin table. Provide the Java environment and the Plugin which - // can be used to override the defaults if the plugin wants. - initializeBrowserFuncs(); - memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); - m_pluginFuncs.size = sizeof(m_pluginFuncs); - if(m_NP_Initialize(&m_browserFuncs, - &m_pluginFuncs, - m_env, - pluginObject) != NPERR_NO_ERROR) { - PLUGIN_LOG("Couldn't initialize plugin\n"); - return false; - } - - // Add the Plugin to the PluginList - jobject pluginListObject = getPluginListObject(); - if(!pluginListObject) { - PLUGIN_LOG("Couldn't get PluginList object\n"); - m_NP_Shutdown(); - return false; - } - if(!addPluginObjectToList(pluginListObject, pluginObject)) { - PLUGIN_LOG("Couldn't add Plugin to PluginList\n"); - m_NP_Shutdown(); - return false; - } - - // Retain the Java Plugin object - m_pluginObject = m_env->NewGlobalRef(pluginObject); - - // Need to call NP_Shutdown at some point in the future. - m_libraryInitialized = true; - - // Don't close the library - loaded OK. - dlCloser.ok(); - // Retain the handle so we can close it in the future. - m_libraryHandle = handle; - - PLUGIN_LOG("Loaded OK\n"); - return true; -} - -void PluginPackageAndroid::unload() -{ - if(!m_libraryHandle) { - PLUGIN_LOG("Plugin \"%s\" already unloaded\n", m_path.utf8().data()); - return; // No library loaded - } - PLUGIN_LOG("Unloading \"%s\"\n", m_path.utf8().data()); - - if(m_libraryInitialized) { - // Shutdown the plug-in - ASSERT(m_NP_Shutdown != NULL); - PLUGIN_LOG("Calling NP_Shutdown\n"); - NPError err = m_NP_Shutdown(); - if(err != NPERR_NO_ERROR) - PLUGIN_LOG("Couldn't shutdown plug-in \"%s\"\n", - m_path.utf8().data()); - m_libraryInitialized = false; - - // Remove the plugin from the PluginList - if(m_pluginObject) { - jobject pluginListObject = getPluginListObject(); - if(pluginListObject) { - removePluginObjectFromList(pluginListObject, m_pluginObject); - } - // Remove a reference to the Plugin object so it can - // garbage collect. - m_env->DeleteGlobalRef(m_pluginObject); - m_pluginObject = 0; - } - } - - PLUGIN_LOG("Closing library\n"); - dlclose(m_libraryHandle); - m_libraryHandle = 0; - memset(&m_browserFuncs, 0, sizeof(m_browserFuncs)); - memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); - m_NP_Initialize = 0; - m_NP_Shutdown = 0; - m_NP_GetMIMEDescription = 0; - m_NP_GetValue = 0; -} - -const NPPluginFuncs* PluginPackageAndroid::pluginFuncs() const -{ - ASSERT(m_libraryHandle && m_libraryInitialized); - return &m_pluginFuncs; -} - -PluginPackageAndroid* PluginPackageAndroid::createPackage(const String& path, - uint32 lastModified) -{ - PluginPackageAndroid* package = new PluginPackageAndroid(path, - lastModified); - - if (!package->load()) { - delete package; - return 0; - } - - return package; -} - -bool PluginPackageAndroid::getEntryPoint(const char *name, void **entry_point) -{ - dlerror(); - *entry_point = dlsym(m_libraryHandle, name); - const char *error = dlerror(); - if(error == NULL && *entry_point != NULL) { - return true; - } else { - PLUGIN_LOG("Couldn't get entry point \"%s\": %s\n", - name, error); - return false; - } -} - -bool PluginPackageAndroid::initializeMIMEEntry(const String& mimeEntry) -{ - // Each part is split into 3 fields separated by colons - // Field 1 is the MIME type (e.g "application/x-shockwave-flash"). - // Field 2 is a comma separated list of file extensions. - // Field 3 is a human readable short description. - Vector<String> fields = mimeEntry.split(':', true); - if(fields.size() != 3) - return false; - - const String& mimeType = fields[0]; - Vector<String> extensions = fields[1].split(',', true); - const String& description = fields[2]; - - PLUGIN_LOG("mime_type: \"%s\"\n", - mimeType.utf8().data()); - PLUGIN_LOG("extensions: \"%s\"\n", - fields[1].utf8().data()); - PLUGIN_LOG("description: \"%s\"\n", - description.utf8().data()); - - // Map the mime type to the vector of extensions and the description - if(!extensions.isEmpty()) - m_mimeToExtensions.set(mimeType, extensions); - if(!description.isEmpty()) - m_mimeToDescriptions.set(mimeType, description); - - return true; -} - -bool PluginPackageAndroid::initializeMIMEDescription( - const String& mimeDescription) -{ - PLUGIN_LOG("MIME description: \"%s\"\n", mimeDescription.utf8().data()); - - // Clear out the current mappings. - m_mimeToDescriptions.clear(); - m_mimeToExtensions.clear(); - - // Split the description into its component entries, separated by - // semicolons. - Vector<String> mimeEntries = mimeDescription.split(';', true); - - // Iterate through the entries, adding them to the MIME mappings. - for(Vector<String>::const_iterator it = mimeEntries.begin(); - it != mimeEntries.end(); ++it) { - if(!initializeMIMEEntry(*it)) { - PLUGIN_LOG("Bad MIME entry: \"%s\"\n", it->utf8().data()); - m_mimeToDescriptions.clear(); - m_mimeToExtensions.clear(); - return false; - } - } - - return true; -} - -PluginPackageAndroid::DynamicLibraryCloser::~DynamicLibraryCloser() -{ - // Close the PluginPackageAndroid's library - if(m_package) - { - if(m_package->m_libraryHandle) - { - dlclose(m_package->m_libraryHandle); - m_package->m_libraryHandle = NULL; - } - m_package = NULL; - } -} - -} // namespace WebCore - -#endif diff --git a/WebCore/plugins/android/PluginPackageAndroid.h b/WebCore/plugins/android/PluginPackageAndroid.h deleted file mode 100644 index d78df1e..0000000 --- a/WebCore/plugins/android/PluginPackageAndroid.h +++ /dev/null @@ -1,152 +0,0 @@ -#ifdef ANDROID_PLUGINS - -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PluginPackageAndroid_H -#define PluginPackageAndroid_H - -#include "PlatformString.h" -#include "StringHash.h" -#include "Timer.h" -#include "npfunctions.h" -#include <wtf/HashMap.h> -#include "wtf/RefCounted.h" - -namespace WebCore { - typedef HashMap<String, String> MIMEToDescriptionsMap; - typedef HashMap<String, Vector<String> > MIMEToExtensionsMap; - - class PluginPackageAndroid : public RefCounted<PluginPackageAndroid> { - public: - ~PluginPackageAndroid(); - static PluginPackageAndroid* createPackage(const String& path, - uint32 lastModified); - - String path() const { return m_path; } - String name() const { return m_name; } - String fileName() const { return m_fileName; } - String description() const { return m_description; } - uint32 getLastModified() const { return m_lastModified; } - - const MIMEToDescriptionsMap& mimeToDescriptions() const { - return m_mimeToDescriptions; - } - const MIMEToExtensionsMap& mimeToExtensions() const { - return m_mimeToExtensions; - } - - bool load(); - void unload(); - - const NPPluginFuncs* pluginFuncs() const; - - private: - // Simple class which calls dlclose() on a dynamic library when going - // out of scope. Call ok() if the handle should stay open. - class DynamicLibraryCloser - { - public: - DynamicLibraryCloser(PluginPackageAndroid *package) - : m_package(package) { } - ~DynamicLibraryCloser(); - void ok() { m_package = NULL; } - private: - PluginPackageAndroid *m_package; - }; - friend class DynamicLibraryCloser; - - PluginPackageAndroid(const String& path, - uint32 lastModified); - - // Set all the NPN function pointers in m_browserFuncs - void initializeBrowserFuncs(); - - // Call dlsym() and set *entry_point to the return value for - // the symbol 'name'. Return true if the symbol exists. - bool getEntryPoint(const char *name, void **entry_point); - - // Initialize m_mimeToDescriptions and m_mimeToExtensions from - // this individual MIME entry. If badly formatted, returns - // false. - bool initializeMIMEEntry(const String& mime_entry); - - // Splits the MIME description into its entries and passes - // them to initializeMIMEEntry. Returns false if any of the - // description is badly format. - bool initializeMIMEDescription(const String& mime_description); - - // Create a Java Plugin object instance - jobject createPluginObject(const char *name, - const char *path, - const char *fileName, - const char *description); - - // Get hold of the Java PluginList instance. - jobject getPluginListObject(); - - // Add the plugin to the PluginList. - bool addPluginObjectToList(jobject pluginList, - jobject plugin); - - // Remove the plugin from the Pluginlist - void removePluginObjectFromList(jobject pluginList, - jobject plugin); - - String m_path; // Path to open this library - String m_name; // Human readable name e.g "Shockwave Flash" - String m_fileName; // Name of the file e.g "libflashplayer.so" - String m_description; // Verbose string e.g "Shockwave Flash 9.0 r48" - uint32 m_lastModified; // Last modification time, Unix seconds. - - NPNetscapeFuncs m_browserFuncs; - NPPluginFuncs m_pluginFuncs; - MIMEToDescriptionsMap m_mimeToDescriptions; - MIMEToExtensionsMap m_mimeToExtensions; - - // The Java environment. - JNIEnv *m_env; - - // The Java Plugin object. - jobject m_pluginObject; - - // Handle to the dynamic library. Non-NULL if open. - void *m_libraryHandle; - - // True if the library is in the initialized state - // (NP_Initialize called) - bool m_libraryInitialized; - - // Entry points into the library obtained using dlsym() - NP_InitializeFuncPtr m_NP_Initialize; - NP_ShutdownFuncPtr m_NP_Shutdown; - NP_GetMIMEDescriptionFuncPtr m_NP_GetMIMEDescription; - NP_GetValueFuncPtr m_NP_GetValue; - }; -} // namespace WebCore - -#endif - -#endif diff --git a/WebCore/plugins/android/PluginViewAndroid.cpp b/WebCore/plugins/android/PluginViewAndroid.cpp deleted file mode 100644 index 87dbe11..0000000 --- a/WebCore/plugins/android/PluginViewAndroid.cpp +++ /dev/null @@ -1,567 +0,0 @@ -#ifdef ANDROID_PLUGINS - -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "PluginViewAndroid.h" - -#include "Document.h" -#include "Element.h" -#include "FrameLoader.h" -#include "FrameLoadRequest.h" -#include "FrameTree.h" -#include "Frame.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HTMLNames.h" -#include "HTMLPlugInElement.h" -#include "Image.h" -#include "MIMETypeRegistry.h" -#include "NotImplemented.h" -#include "Page.h" -#include "PlatformGraphicsContext.h" -#include "PluginPackageAndroid.h" -#include "kjs_binding.h" -#include "kjs_proxy.h" -#include "kjs_window.h" -#include "android_graphics.h" -#include "SkCanvas.h" -#include "npruntime_impl.h" -#include "runtime_root.h" -#include "Settings.h" -#include <kjs/JSLock.h> -#include <kjs/value.h> -#include <wtf/ASCIICType.h> -#include "runtime.h" -#include "WebViewCore.h" - -#include "PluginDebug.h" - -using KJS::ExecState; -using KJS::Interpreter; -using KJS::JSLock; -using KJS::JSObject; -using KJS::JSValue; -using KJS::UString; - -using std::min; - -using namespace WTF; - -namespace WebCore { - -using namespace HTMLNames; - -PluginViewAndroid* PluginViewAndroid::s_currentPluginView = 0; - -void PluginViewAndroid::setParent(ScrollView* parent) -{ - if (parent) - init(); -} - -bool PluginViewAndroid::start() -{ - if (m_isStarted) - return false; - - ASSERT(m_plugin); - ASSERT(m_plugin->pluginFuncs()->newp); - - NPError npErr; - PluginViewAndroid::setCurrentPluginView(this); - { - KJS::JSLock::DropAllLocks dropAllLocks; - npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.data(), - m_instance, - m_mode, - m_paramCount, - m_paramNames, - m_paramValues, - NULL); - if(npErr) - PLUGIN_LOG("plugin->newp returned %d\n", static_cast<int>(npErr)); - } - PluginViewAndroid::setCurrentPluginView(0); - - if (npErr != NPERR_NO_ERROR) - return false; - - m_isStarted = true; - - return true; -} - -void PluginViewAndroid::stop() -{ - if (!m_isStarted) - return; - - m_isStarted = false; - - KJS::JSLock::DropAllLocks dropAllLocks; - - // Destroy the plugin - NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, 0); - if(npErr) - PLUGIN_LOG("Plugin destroy returned %d\n", static_cast<int>(npErr)); - - m_instance->pdata = 0; -} - -void PluginViewAndroid::setCurrentPluginView(PluginViewAndroid* pluginView) -{ - s_currentPluginView = pluginView; -} - -PluginViewAndroid* PluginViewAndroid::currentPluginView() -{ - return s_currentPluginView; -} - -static char* createUTF8String(const String& str) -{ - CString cstr = str.utf8(); - char* result = reinterpret_cast<char*>(fastMalloc(cstr.length() + 1)); - - strncpy(result, cstr.data(), cstr.length() + 1); - - return result; -} - -static void freeStringArray(char** stringArray, int length) -{ - if (!stringArray) - return; - - for (int i = 0; i < length; i++) - fastFree(stringArray[i]); - - fastFree(stringArray); -} - -NPError PluginViewAndroid::getURLNotify(const char* url, - const char* target, - void* notifyData) -{ - notImplemented(); - return NPERR_GENERIC_ERROR; -} - -NPError PluginViewAndroid::getURL(const char* url, const char* target) -{ - notImplemented(); - return NPERR_GENERIC_ERROR; -} - -NPError PluginViewAndroid::postURLNotify(const char* url, - const char* target, - uint32 len, - const char* buf, - NPBool file, - void* notifyData) -{ - notImplemented(); - return NPERR_GENERIC_ERROR; -} - -NPError PluginViewAndroid::postURL(const char* url, - const char* target, - uint32 len, - const char* buf, - NPBool file) -{ - notImplemented(); - return NPERR_GENERIC_ERROR; -} - -NPError PluginViewAndroid::newStream(NPMIMEType type, - const char* target, - NPStream** stream) -{ - notImplemented(); - return NPERR_GENERIC_ERROR; -} - -int32 PluginViewAndroid::write(NPStream* stream, - int32 len, - void* buffer) -{ - notImplemented(); - return -1; -} - -NPError PluginViewAndroid::destroyStream(NPStream* stream, NPReason reason) -{ - notImplemented(); - return NPERR_GENERIC_ERROR; -} - -const char* PluginViewAndroid::userAgent() -{ - if (m_userAgent.isNull()) - m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8(); - return m_userAgent.data(); -} - -void PluginViewAndroid::status(const char* message) -{ - String s = DeprecatedString::fromLatin1(message); - - if (Page* page = m_parentFrame->page()) - page->chrome()->setStatusbarText(m_parentFrame, s); -} - -NPError PluginViewAndroid::getValue(NPNVariable variable, void* value) -{ - switch (variable) { - case NPNVWindowNPObject: { - NPObject* windowScriptObject = - m_parentFrame->windowScriptNPObject(); - - // Return value is expected to be retained, as described - // here: - // <http://www.mozilla.org/projects/plugin/npruntime.html> - if (windowScriptObject) - _NPN_RetainObject(windowScriptObject); - - void** v = (void**)value; - *v = windowScriptObject; - - return NPERR_NO_ERROR; - } - - case NPNVPluginElementNPObject: { - NPObject* pluginScriptObject = 0; - - if (m_element->hasTagName(appletTag) || - m_element->hasTagName(embedTag) || - m_element->hasTagName(objectTag)) { - HTMLPlugInElement* pluginElement = - static_cast<HTMLPlugInElement*>(m_element); - pluginScriptObject = pluginElement->getNPObject(); - } - - // Return value is expected to be retained, as described - // here: - // <http://www.mozilla.org/projects/plugin/npruntime.html> - if (pluginScriptObject) - _NPN_RetainObject(pluginScriptObject); - - void** v = (void**)value; - *v = pluginScriptObject; - - return NPERR_NO_ERROR; - } - - case NPNVnetscapeWindow: { - // Return the top level WebView Java object associated - // with this instance. - jobject *retObject = static_cast<jobject*>(value); - // Dig down through to the parent frame's WebCoreViewBridge - FrameView* frameView = m_parentFrame->view(); - WebCoreViewBridge* bridge = frameView->getWebCoreViewBridge(); - // Go up parents until we reach the top level. - while (bridge->getParent() != NULL) - bridge = bridge->getParent(); - // This is actually an instance of WebCoreView. - android::WebViewCore* webViewCore = - static_cast<android::WebViewCore*>(bridge); - // Finally, get hold of the Java WebView instance. - *retObject = webViewCore->getWebViewJavaObject(); - return NPERR_NO_ERROR; - } - default: - return NPERR_GENERIC_ERROR; - } -} - -NPError PluginViewAndroid::setValue(NPPVariable variable, void* value) -{ - switch (variable) { - case NPPVpluginWindowBool: - m_isWindowed = value; - return NPERR_NO_ERROR; - case NPPVpluginTransparentBool: - m_isTransparent = value; - return NPERR_NO_ERROR; - default: - notImplemented(); - return NPERR_GENERIC_ERROR; - } -} - -void PluginViewAndroid::invalidateRect(NPRect* rect) -{ - notImplemented(); -} - -void PluginViewAndroid::invalidateRegion(NPRegion region) -{ - notImplemented(); -} - -void PluginViewAndroid::forceRedraw() -{ - notImplemented(); -} - -KJS::Bindings::Instance* PluginViewAndroid::bindingInstance() -{ - NPObject* object = 0; - - if (!m_plugin || !m_plugin->pluginFuncs()->getvalue) - return 0; - - NPError npErr; - { - KJS::JSLock::DropAllLocks dropAllLocks; - npErr = m_plugin->pluginFuncs()->getvalue(m_instance, - NPPVpluginScriptableNPObject, - &object); - } - - if (npErr != NPERR_NO_ERROR || !object) - return 0; - - RefPtr<KJS::Bindings::RootObject> root = m_parentFrame->createRootObject( - this, - m_parentFrame->scriptProxy()->globalObject()); - KJS::Bindings::Instance *instance = - KJS::Bindings::Instance::createBindingForLanguageInstance( - KJS::Bindings::Instance::CLanguage, - object, - root.release()); - - _NPN_ReleaseObject(object); - - return instance; -} - -PluginViewAndroid::~PluginViewAndroid() -{ - stop(); - - freeStringArray(m_paramNames, m_paramCount); - freeStringArray(m_paramValues, m_paramCount); - - m_parentFrame->cleanupScriptObjectsForPlugin(this); - - // Don't unload the plugin - let the reference count clean it up. - - // Can't use RefPtr<> because it's name clashing with SkRefCnt<> - m_viewBridge->unref(); -} - -void PluginViewAndroid::setParameters(const Vector<String>& paramNames, - const Vector<String>& paramValues) -{ - ASSERT(paramNames.size() == paramValues.size()); - - // Also pass an extra parameter - unsigned size = paramNames.size() + 1; - unsigned paramCount = 0; - - m_paramNames = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size)); - m_paramValues = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size)); - - for (unsigned i = 0; i < paramNames.size(); i++) { - if (equalIgnoringCase(paramNames[i], "windowlessvideo")) - continue; - // Don't let the HTML element specify this value! - if (equalIgnoringCase(paramNames[i], "android_plugins_dir")) - continue; - - m_paramNames[paramCount] = createUTF8String(paramNames[i]); - m_paramValues[paramCount] = createUTF8String(paramValues[i]); - - paramCount++; - } - - // Pass the location of the plug-ins directory so the plug-in - // knows where it can store any data it needs. - WebCore::String path = m_parentFrame->settings()->pluginsPath(); - m_paramNames[paramCount] = createUTF8String("android_plugins_dir"); - m_paramValues[paramCount] = createUTF8String(path.utf8().data()); - paramCount++; - - m_paramCount = paramCount; -} - -PluginViewAndroid::PluginViewAndroid(Frame* parentFrame, - const IntSize& size, - PluginPackageAndroid* plugin, - Element* element, - const KURL& url, - const Vector<String>& paramNames, - const Vector<String>& paramValues, - const String& mimeType, - bool loadManually) - : m_plugin(plugin) - , m_element(element) - , m_parentFrame(parentFrame) - , m_userAgent() - , m_isStarted(false) - , m_url(url) - , m_status(PluginStatusLoadedSuccessfully) - , m_mode(0) - , m_paramCount(0) - , m_paramNames(0) - , m_paramValues(0) - , m_mimeType() - , m_instance() - , m_instanceStruct() - , m_isWindowed(true) - , m_isTransparent(false) - , m_haveInitialized(false) - , m_lastMessage(0) - , m_loadManually(loadManually) - , m_viewBridge(new PluginViewBridgeAndroid()) -{ - setWebCoreViewBridge(m_viewBridge); - - if (!m_plugin) { - m_status = PluginStatusCanNotFindPlugin; - return; - } - - m_instance = &m_instanceStruct; - m_instance->ndata = this; - - m_mimeType = mimeType.utf8(); - - setParameters(paramNames, paramValues); - - m_mode = m_loadManually ? NP_FULL : NP_EMBED; - - resize(size); - - // Early initialisation until we can properly parent this - init(); -} - -void PluginViewAndroid::init() -{ - if (m_haveInitialized) - return; - m_haveInitialized = true; - - if (!m_plugin) { - ASSERT(m_status == PluginStatusCanNotFindPlugin); - return; - } - - if (!m_plugin->load()) { - m_plugin = 0; - m_status = PluginStatusCanNotLoadPlugin; - return; - } - - if (!start()) { - m_status = PluginStatusCanNotLoadPlugin; - return; - } - - m_status = PluginStatusLoadedSuccessfully; -} - -PluginViewBridgeAndroid::PluginViewBridgeAndroid() -{ - m_image = Image::loadPlatformResource("nullplugin"); - if(m_image) - setSize(m_image->width(), m_image->height()); - else - PLUGIN_LOG("Couldn't get nullplugin image\n"); -} - -PluginViewBridgeAndroid::~PluginViewBridgeAndroid() -{ - delete m_image; -} - -void PluginViewBridgeAndroid::draw(GraphicsContext* gc, - const IntRect& rect, - bool) -{ - if (gc->paintingDisabled() || !m_image) - return; - - // Clip the drawing rectangle to our bounds in case it is larger. - IntRect transRect(rect); - IntRect bounds = this->getBounds(); - transRect.intersect(bounds); - - // Move the drawing rectangle into our coordinate space. - transRect.move(-bounds.x(), -bounds.y()); - - // Translate the canvas by the view's location so that things will draw - // in the right place. Clip the canvas to the drawing rectangle. - SkRect r; - android_setrect(&r, transRect); - if (r.isEmpty()) - return; - SkCanvas* canvas = gc->platformContext()->mCanvas; - canvas->save(); - canvas->translate(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y())); - canvas->clipRect(r); - - // Calculate where to place the image so it appears in the center of the - // view. - int imageWidth = m_image->width(); - int imageHeight = m_image->height(); - IntRect centerRect(0, 0, imageWidth, imageHeight); - IntSize c1(bounds.width()/2, bounds.height()/2); - IntSize c2(centerRect.width()/2, centerRect.height()/2); - IntSize diff = c1 - c2; - centerRect.move(diff); - - // Now move the top-left corner of the image to the top-left corner of - // the view so that the tiling will hit the center image. - while (diff.width() > 0) - diff.setWidth(diff.width() - imageWidth); - while (diff.height() > 0) - diff.setHeight(diff.height() - imageHeight); - - // Draw the tiled transparent image adding one extra image width and - // height so that we get a complete fill. - gc->beginTransparencyLayer(0.1); - gc->drawTiledImage(m_image, - IntRect(diff.width(), diff.height(), - bounds.width() + imageWidth, - bounds.height() + imageHeight), - IntPoint(0, 0), IntSize(imageWidth, imageHeight)); - gc->endTransparencyLayer(); - - // Draw the image in the center. - gc->drawImage(m_image, centerRect); - - // Restore our canvas - canvas->restore(); -} - -} // namespace WebCore - -#endif // defined(ANDROID_PLUGINS) diff --git a/WebCore/plugins/android/PluginViewAndroid.h b/WebCore/plugins/android/PluginViewAndroid.h deleted file mode 100644 index d4e55b8..0000000 --- a/WebCore/plugins/android/PluginViewAndroid.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifdef ANDROID_PLUGINS - -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PluginViewAndroid_H -#define PluginViewAndroid_H - -#include "CString.h" -#include "IntRect.h" -#include "KURL.h" -#include "PlatformString.h" -#include "ResourceRequest.h" -#include "Widget.h" -#include "npapi.h" -#include "WebCoreViewBridge.h" -#include <wtf/HashMap.h> -#include <wtf/HashSet.h> -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> - -namespace KJS { - namespace Bindings { - class Instance; - } -} - -namespace WebCore { - class Element; - class Frame; - class Image; - class KURL; - class PluginPackageAndroid; - - enum PluginStatus { - PluginStatusCanNotFindPlugin, - PluginStatusCanNotLoadPlugin, - PluginStatusLoadedSuccessfully - }; - - class PluginViewBridgeAndroid : public WebCoreViewBridge { - public: - PluginViewBridgeAndroid(); - ~PluginViewBridgeAndroid(); - virtual void draw(GraphicsContext* gc, const IntRect& rect, bool); - private: - Image* m_image; - }; - - class PluginViewAndroid : public Widget { - public: - PluginViewAndroid(Frame* parentFrame, - const IntSize&, - PluginPackageAndroid* plugin, - Element*, - const KURL&, - const Vector<String>& paramNames, - const Vector<String>& paramValues, - const String& mimeType, - bool loadManually); - virtual ~PluginViewAndroid(); - - PluginPackageAndroid* plugin() const { return m_plugin.get(); } - NPP instance() const { return m_instance; } - - static PluginViewAndroid* currentPluginView(); - - KJS::Bindings::Instance* bindingInstance(); - - PluginStatus status() const { return m_status; } - - // NPN stream functions - NPError getURLNotify(const char* url, - const char* target, - void* notifyData); - NPError getURL(const char* url, - const char* target); - NPError postURLNotify(const char* url, - const char* target, - uint32 len, - const char* but, - NPBool file, - void* notifyData); - NPError postURL(const char* url, - const char* target, - uint32 len, - const char* but, - NPBool file); - NPError newStream(NPMIMEType type, - const char* target, - NPStream** stream); - int32 write(NPStream* stream, int32 len, void* buffer); - NPError destroyStream(NPStream* stream, NPReason reason); - - // NPN misc functions - const char* userAgent(); - void status(const char* message); - NPError getValue(NPNVariable variable, void* value); - NPError setValue(NPPVariable variable, void* value); - - // NPN UI functions - void invalidateRect(NPRect*); - void invalidateRegion(NPRegion); - void forceRedraw(); - - // Widget functions - virtual void setParent(ScrollView*); - - private: - void setParameters(const Vector<String>& paramNames, - const Vector<String>& paramValues); - void init(); - bool start(); - void stop(); - static void setCurrentPluginView(PluginViewAndroid*); - - // Maintain a refcount on the plugin. It should be deleted - // once all views no longer reference it. - RefPtr<PluginPackageAndroid> m_plugin; - Element* m_element; - Frame* m_parentFrame; - CString m_userAgent; - bool m_isStarted; - KURL m_url; - PluginStatus m_status; - - int m_mode; - int m_paramCount; - char** m_paramNames; - char** m_paramValues; - - CString m_mimeType; - NPP m_instance; - NPP_t m_instanceStruct; - - bool m_isWindowed; - bool m_isTransparent; - bool m_haveInitialized; - - unsigned m_lastMessage; - - bool m_loadManually; - - // Sorry, can't use RefPtr<> due to name collision with SkRefCnt. - PluginViewBridgeAndroid *m_viewBridge; - - static PluginViewAndroid* s_currentPluginView; - }; - -} // namespace WebCore - -#endif - -#endif // defined(ANDROID_PLUGINS) diff --git a/WebCore/plugins/android/npapi.cpp b/WebCore/plugins/android/npapi.cpp deleted file mode 100644 index 23007eb..0000000 --- a/WebCore/plugins/android/npapi.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#ifdef ANDROID_PLUGINS -// Needed for NPN_PluginThreadAsyncCall, which calls -// JavaSharedClient::EnqueueFunctionPtr(). -#include "JavaSharedClient.h" -#endif -#include "WebCoreJni.h" -#include "PluginInfoStore.h" -#include "PluginViewAndroid.h" -#include "jni.h" -#include "npapi.h" - -#include "PluginDebug.h" - -using namespace WebCore; - -// The plugin view is always the ndata of the instance,. Sometimes, plug-ins will call an instance-specific function -// with a NULL instance. To workaround this, call the last plug-in view that made a call to a plug-in. -// Currently, the current plug-in view is only set before NPP_New in PluginViewAndroid::start. -// This specifically works around Flash and Shockwave. When we call NPP_New, they call NPN_Useragent with a NULL instance. -static PluginViewAndroid* pluginViewForInstance(NPP instance) -{ - if (instance && instance->ndata) - return static_cast<PluginViewAndroid*>(instance->ndata); - return PluginViewAndroid::currentPluginView(); -} - -void* NPN_MemAlloc(uint32 size) -{ - return malloc(size); -} - -void NPN_MemFree(void* ptr) -{ - free(ptr); -} - -uint32 NPN_MemFlush(uint32 size) -{ - // Do nothing - return 0; -} - -void NPN_ReloadPlugins(NPBool reloadPages) -{ - refreshPlugins(reloadPages); -} - -NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList) -{ - return NPERR_STREAM_NOT_SEEKABLE; -} - -NPError NPN_GetURLNotify(NPP instance, const char* url, const char* target, void* notifyData) -{ - return pluginViewForInstance(instance)->getURLNotify(url, target, notifyData); -} - -NPError NPN_GetURL(NPP instance, const char* url, const char* target) -{ - return pluginViewForInstance(instance)->getURL(url, target); -} - -NPError NPN_PostURLNotify(NPP instance, const char* url, const char* target, uint32 len, const char* buf, NPBool file, void* notifyData) -{ - return pluginViewForInstance(instance)->postURLNotify(url, target, len, buf, file, notifyData); -} - -NPError NPN_PostURL(NPP instance, const char* url, const char* target, uint32 len, const char* buf, NPBool file) -{ - return pluginViewForInstance(instance)->postURL(url, target, len, buf, file); -} - -NPError NPN_NewStream(NPP instance, NPMIMEType type, const char* target, NPStream** stream) -{ - return pluginViewForInstance(instance)->newStream(type, target, stream); -} - -int32 NPN_Write(NPP instance, NPStream* stream, int32 len, void* buffer) -{ - return pluginViewForInstance(instance)->write(stream, len, buffer); -} - -NPError NPN_DestroyStream(NPP instance, NPStream* stream, NPReason reason) -{ - return pluginViewForInstance(instance)->destroyStream(stream, reason); -} - -const char* NPN_UserAgent(NPP instance) -{ - PluginViewAndroid* view = pluginViewForInstance(instance); - - // FIXME: Some plug-ins call NPN_UserAgent with a null instance in their NP_initialize function! - // We'd need a way to get a user agent without having a frame around. - if (!view) - return 0; - - return view->userAgent(); -} - -void NPN_Status(NPP instance, const char* message) -{ - pluginViewForInstance(instance)->status(message); -} - -void NPN_InvalidateRect(NPP instance, NPRect* invalidRect) -{ - pluginViewForInstance(instance)->invalidateRect(invalidRect); -} - -void NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion) -{ - pluginViewForInstance(instance)->invalidateRegion(invalidRegion); -} - -void NPN_ForceRedraw(NPP instance) -{ - pluginViewForInstance(instance)->forceRedraw(); -} - -NPError NPN_GetValue(NPP instance, NPNVariable variable, void* value) -{ - return pluginViewForInstance(instance)->getValue(variable, value); -} - -NPError NPN_SetValue(NPP instance, NPPVariable variable, void* value) -{ - return pluginViewForInstance(instance)->setValue(variable, value); -} - -void* NPN_GetJavaEnv() -{ - // This is supposed to return the JRIEnv, but nobody's been using - // that interface for years. Far more useful to return the JNIEnv, - // so we'll do that... - JNIEnv* env = NULL; - if (android::WebCoreJni::getJavaVM()->GetEnv((void**) &env, - JNI_VERSION_1_4) != JNI_OK) { - PLUGIN_LOG("GetEnv failed!"); - } - return env; -} - -void* NPN_GetJavaPeer(NPP instance) -{ - // Unsupported - return 0; -} - -void -NPN_PushPopupsEnabledState(NPP instance, NPBool enabled) -{ -} - -void -NPN_PopPopupsEnabledState(NPP instance) -{ -} - -#ifdef ANDROID_PLUGINS -// Added in version 19 NPAPI. Sandbox WebKit has this same function in -// plugins/npapi.cpp rather than plugins/android/npapi.cpp. This file -// goes away after merge. -void NPN_PluginThreadAsyncCall(NPP instance, - void (*func)(void *), - void *userData) -{ - // This is used to marshal a function call onto the main thread, - // so plugins can get around not "owning" the message loop. Note - // that the plugin is responsible for taking care of the potential - // race between the order of NPP_Destroy and callbacks. - JavaSharedClient::EnqueueFunctionPtr(func, userData); -} -#endif diff --git a/WebCore/plugins/android/npfunctions.h b/WebCore/plugins/android/npfunctions.h deleted file mode 100644 index f9a5612..0000000 --- a/WebCore/plugins/android/npfunctions.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _NPFUNCTIONS_H_ -#define _NPFUNCTIONS_H_ - -#include <jni.h> -#include "npruntime.h" -#include "npapi.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(XP_WIN) -#define EXPORTED_CALLBACK(_type, _name) _type (__stdcall * _name) -#else -#define EXPORTED_CALLBACK(_type, _name) _type (* _name) -#endif - -typedef NPError (*NPN_GetURLNotifyProcPtr)(NPP instance, const char* URL, const char* window, void* notifyData); -typedef NPError (*NPN_PostURLNotifyProcPtr)(NPP instance, const char* URL, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData); -typedef NPError (*NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList); -typedef NPError (*NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** stream); -typedef int32 (*NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32 len, void* buffer); -typedef NPError (*NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); -typedef void (*NPN_StatusProcPtr)(NPP instance, const char* message); -typedef const char*(*NPN_UserAgentProcPtr)(NPP instance); -typedef void* (*NPN_MemAllocProcPtr)(uint32 size); -typedef void (*NPN_MemFreeProcPtr)(void* ptr); -typedef uint32 (*NPN_MemFlushProcPtr)(uint32 size); -typedef void (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages); -typedef NPError (*NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value); -typedef NPError (*NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value); -typedef void (*NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect); -typedef void (*NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region); -typedef void (*NPN_ForceRedrawProcPtr)(NPP instance); -typedef NPError (*NPN_GetURLProcPtr)(NPP instance, const char* URL, const char* window); -typedef NPError (*NPN_PostURLProcPtr)(NPP instance, const char* URL, const char* window, uint32 len, const char* buf, NPBool file); -typedef void* (*NPN_GetJavaEnvProcPtr)(void); -typedef void* (*NPN_GetJavaPeerProcPtr)(NPP instance); -typedef void (*NPN_PushPopupsEnabledStateProcPtr)(NPP instance, NPBool enabled); -typedef void (*NPN_PopPopupsEnabledStateProcPtr)(NPP instance); - -typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant); - -typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr) (const NPUTF8 *name); -typedef void (*NPN_GetStringIdentifiersProcPtr) (const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers); -typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr) (int32_t intid); -typedef int32_t (*NPN_IntFromIdentifierProcPtr) (NPIdentifier identifier); -typedef bool (*NPN_IdentifierIsStringProcPtr) (NPIdentifier identifier); -typedef NPUTF8 *(*NPN_UTF8FromIdentifierProcPtr) (NPIdentifier identifier); - -typedef NPObject* (*NPN_CreateObjectProcPtr) (NPP, NPClass *aClass); -typedef NPObject* (*NPN_RetainObjectProcPtr) (NPObject *obj); -typedef void (*NPN_ReleaseObjectProcPtr) (NPObject *obj); -typedef bool (*NPN_InvokeProcPtr) (NPP npp, NPObject *obj, NPIdentifier methodName, const NPVariant *args, unsigned argCount, NPVariant *result); -typedef bool (*NPN_InvokeDefaultProcPtr) (NPP npp, NPObject *obj, const NPVariant *args, unsigned argCount, NPVariant *result); -typedef bool (*NPN_EvaluateProcPtr) (NPP npp, NPObject *obj, NPString *script, NPVariant *result); -typedef bool (*NPN_GetPropertyProcPtr) (NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); -typedef bool (*NPN_SetPropertyProcPtr) (NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); -typedef bool (*NPN_HasPropertyProcPtr) (NPP, NPObject *npobj, NPIdentifier propertyName); -typedef bool (*NPN_HasMethodProcPtr) (NPP npp, NPObject *npobj, NPIdentifier methodName); -typedef bool (*NPN_RemovePropertyProcPtr) (NPP npp, NPObject *obj, NPIdentifier propertyName); -typedef void (*NPN_SetExceptionProcPtr) (NPObject *obj, const NPUTF8 *message); -typedef bool (*NPN_EnumerateProcPtr) (NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count); -#ifdef ANDROID_PLUGINS -// Added in version 19 NPAPI. Sandbox WebKit is version 20 and already -// implements this change. -typedef void (*NPN_PluginThreadAsyncCallPtr) (NPP npp, void (*func)(void *), void *userData); -#endif - -typedef NPError (*NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved); -typedef NPError (*NPP_DestroyProcPtr)(NPP instance, NPSavedData** save); -typedef NPError (*NPP_SetWindowProcPtr)(NPP instance, NPWindow* window); -typedef NPError (*NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype); -typedef NPError (*NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); -typedef void (*NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname); -typedef int32 (*NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream); -typedef int32 (*NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer); -typedef void (*NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint); -typedef int16 (*NPP_HandleEventProcPtr)(NPP instance, void* event); -typedef void (*NPP_URLNotifyProcPtr)(NPP instance, const char* URL, NPReason reason, void* notifyData); -typedef NPError (*NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value); -typedef NPError (*NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value); -typedef EXPORTED_CALLBACK(void, NPP_ShutdownProcPtr)(void); - -typedef void *(*NPP_GetJavaClassProcPtr)(void); -typedef void* JRIGlobalRef; //not using this right now - -typedef struct _NPNetscapeFuncs { - uint16 size; - uint16 version; - - NPN_GetURLProcPtr geturl; - NPN_PostURLProcPtr posturl; - NPN_RequestReadProcPtr requestread; - NPN_NewStreamProcPtr newstream; - NPN_WriteProcPtr write; - NPN_DestroyStreamProcPtr destroystream; - NPN_StatusProcPtr status; - NPN_UserAgentProcPtr uagent; - NPN_MemAllocProcPtr memalloc; - NPN_MemFreeProcPtr memfree; - NPN_MemFlushProcPtr memflush; - NPN_ReloadPluginsProcPtr reloadplugins; - NPN_GetJavaEnvProcPtr getJavaEnv; - NPN_GetJavaPeerProcPtr getJavaPeer; - NPN_GetURLNotifyProcPtr geturlnotify; - NPN_PostURLNotifyProcPtr posturlnotify; - NPN_GetValueProcPtr getvalue; - NPN_SetValueProcPtr setvalue; - NPN_InvalidateRectProcPtr invalidaterect; - NPN_InvalidateRegionProcPtr invalidateregion; - NPN_ForceRedrawProcPtr forceredraw; - - NPN_GetStringIdentifierProcPtr getstringidentifier; - NPN_GetStringIdentifiersProcPtr getstringidentifiers; - NPN_GetIntIdentifierProcPtr getintidentifier; - NPN_IdentifierIsStringProcPtr identifierisstring; - NPN_UTF8FromIdentifierProcPtr utf8fromidentifier; - NPN_IntFromIdentifierProcPtr intfromidentifier; - NPN_CreateObjectProcPtr createobject; - NPN_RetainObjectProcPtr retainobject; - NPN_ReleaseObjectProcPtr releaseobject; - NPN_InvokeProcPtr invoke; - NPN_InvokeDefaultProcPtr invokeDefault; - NPN_EvaluateProcPtr evaluate; - NPN_GetPropertyProcPtr getproperty; - NPN_SetPropertyProcPtr setproperty; - NPN_RemovePropertyProcPtr removeproperty; - NPN_HasPropertyProcPtr hasproperty; - NPN_HasMethodProcPtr hasmethod; - NPN_ReleaseVariantValueProcPtr releasevariantvalue; - NPN_SetExceptionProcPtr setexception; - NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate; - NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate; - NPN_EnumerateProcPtr enumerate; -#ifdef ANDROID_PLUGINS - // Added in version 19 NPAPI. Sandbox WebKit is version 20 and - // already implements this change. - NPN_PluginThreadAsyncCallPtr pluginthreadasynccall; -#endif -} NPNetscapeFuncs; - -typedef struct _NPPluginFuncs { - uint16 size; - uint16 version; - NPP_NewProcPtr newp; - NPP_DestroyProcPtr destroy; - NPP_SetWindowProcPtr setwindow; - NPP_NewStreamProcPtr newstream; - NPP_DestroyStreamProcPtr destroystream; - NPP_StreamAsFileProcPtr asfile; - NPP_WriteReadyProcPtr writeready; - NPP_WriteProcPtr write; - NPP_PrintProcPtr print; - NPP_HandleEventProcPtr event; - NPP_URLNotifyProcPtr urlnotify; - JRIGlobalRef javaClass; - NPP_GetValueProcPtr getvalue; - NPP_SetValueProcPtr setvalue; -} NPPluginFuncs; - -typedef NPError (*NP_InitializeFuncPtr)(NPNetscapeFuncs *netscape_funcs, - NPPluginFuncs *plugin_funcs, - JNIEnv *java_environment, - jobject application_context); -typedef NPError (*NP_ShutdownFuncPtr)(); -typedef char* (*NP_GetMIMEDescriptionFuncPtr)(); -typedef NPError (*NP_GetValueFuncPtr)(void *instance, - NPPVariable var, - void *value); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/WebCore/plugins/gtk/PluginDataGtk.cpp b/WebCore/plugins/gtk/PluginDataGtk.cpp new file mode 100644 index 0000000..0d477cd --- /dev/null +++ b/WebCore/plugins/gtk/PluginDataGtk.cpp @@ -0,0 +1,73 @@ +/* + 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() +{ + PluginDatabase *db = PluginDatabase::installedPlugins(); + const Vector<PluginPackage*> &plugins = db->plugins(); + + for (unsigned int i = 0; i < plugins.size(); ++i) { + PluginInfo* info = new PluginInfo; + PluginPackage* package = plugins[i]; + + info->name = package->name(); + info->file = package->fileName(); + info->desc = package->description(); + + const MIMEToDescriptionsMap& mimeToDescriptions = package->mimeToDescriptions(); + MIMEToDescriptionsMap::const_iterator end = mimeToDescriptions.end(); + for (MIMEToDescriptionsMap::const_iterator it = mimeToDescriptions.begin(); it != end; ++it) { + MimeClassInfo* mime = new MimeClassInfo; + info->mimes.append(mime); + + mime->type = it->first; + mime->desc = it->second; + mime->plugin = info; + + Vector<String> extensions = package->mimeToExtensions().get(mime->type); + + for (unsigned i = 0; i < extensions.size(); i++) { + if (i > 0) + mime->suffixes += ","; + + mime->suffixes += extensions[i]; + } + } + + m_plugins.append(info); + } +} + +void PluginData::refresh() +{ + PluginDatabase *db = PluginDatabase::installedPlugins(); + db->refresh(); +} + +}; diff --git a/WebCore/plugins/gtk/PluginPackageGtk.cpp b/WebCore/plugins/gtk/PluginPackageGtk.cpp new file mode 100644 index 0000000..5a097b2 --- /dev/null +++ b/WebCore/plugins/gtk/PluginPackageGtk.cpp @@ -0,0 +1,284 @@ +/* + * 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 "CString.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "npruntime_impl.h" +#include "PluginDebug.h" + +namespace WebCore { + +static PlatformModuleVersion getModuleVersion(const char *description) +{ + // 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 + + PlatformModuleVersion version = 0; + + if (!description) + return 0; + + if (g_str_has_prefix(description, "Shockwave Flash ") && strlen(description) >= 19) { + // The flash version as a PlatformModuleVersion differs in GTK 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 in GTK, Flash's version may be + // 0x0a000000 instead of 0x000a0000. This avoids having to modify + // PlatformModuleVersion in the GTK port + + char **version_parts = g_strsplit(description + 16, " ", -1); + if (!version_parts) + return 0; + + int parts_length = g_strv_length(version_parts); + + if (parts_length >= 1) { + guint16 major = 0, minor = 0; + if (sscanf(version_parts[0], "%" G_GUINT16_FORMAT ".%" G_GUINT16_FORMAT, &major, &minor) == 2) + version = ((guint8)major << 24) | ((guint8)minor << 16); + } + + if (parts_length >= 2) { + char *rev_str = version_parts[1]; + if (strlen(rev_str) > 1 && (rev_str[0] == 'r' || rev_str[0] == 'b')) + version |= (guint16)atoi(rev_str + 1); + } + + g_strfreev(version_parts); + } + + return version; +} + +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); + } else { + // Flash 9 and older 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); + } +} + +bool PluginPackage::fetchInfo() +{ +#if defined(XP_UNIX) + if (!load()) + return false; + + NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription; + NPP_GetValueProcPtr NPP_GetValue; + + g_module_symbol(m_module, "NP_GetMIMEDescription", (void**)&NP_GetMIMEDescription); + g_module_symbol(m_module, "NP_GetValue", (void**)&NPP_GetValue); + + 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; + m_moduleVersion = getModuleVersion(buffer); + } + + const gchar* types = NP_GetMIMEDescription(); + gchar** mimeDescs = g_strsplit(types, ";", -1); + for (int i = 0; mimeDescs[i] && mimeDescs[i][0]; i++) { + gchar** mimeData = g_strsplit(mimeDescs[i], ":", 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; + } + + m_module = g_module_open((m_path.utf8()).data(), G_MODULE_BIND_LOCAL); + + if (!m_module) { + LOG(Plugin,"Module Load Failed :%s, Error:%s\n", (m_path.utf8()).data(), g_module_error()); + return false; + } + + m_isLoaded = true; + + NP_InitializeFuncPtr NP_Initialize; + 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); + + 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; + +#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; +} + +unsigned PluginPackage::hash() const +{ + unsigned hashCodes[2] = { + m_path.impl()->hash(), + m_lastModified + }; + + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 2 * sizeof(unsigned) / sizeof(UChar)); +} + +bool PluginPackage::equal(const PluginPackage& a, const PluginPackage& b) +{ + return a.m_description == b.m_description; +} + +int PluginPackage::compareFileVersion(const PlatformModuleVersion& compareVersion) const +{ + // return -1, 0, or 1 if plug-in version is less than, equal to, or greater than + // the passed version + if (m_moduleVersion != compareVersion) + return m_moduleVersion > compareVersion ? 1 : -1; + return 0; +} + +} diff --git a/WebCore/plugins/gtk/PluginViewGtk.cpp b/WebCore/plugins/gtk/PluginViewGtk.cpp new file mode 100644 index 0000000..904e935 --- /dev/null +++ b/WebCore/plugins/gtk/PluginViewGtk.cpp @@ -0,0 +1,586 @@ +/* + * 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 "PluginView.h" + +#include "Document.h" +#include "DocumentLoader.h" +#include "Element.h" +#include "FrameLoader.h" +#include "FrameLoadRequest.h" +#include "FrameTree.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "HTMLNames.h" +#include "HTMLPlugInElement.h" +#include "KeyboardEvent.h" +#include "MouseEvent.h" +#include "NotImplemented.h" +#include "Page.h" +#include "PlatformMouseEvent.h" +#include "PluginDebug.h" +#include "PluginPackage.h" +#include "RenderLayer.h" +#include "Settings.h" +#include "JSDOMBinding.h" +#include "ScriptController.h" +#include "npruntime_impl.h" +#include "runtime.h" +#include "runtime_root.h" +#include <runtime/JSLock.h> +#include <runtime/JSValue.h> + +#include <gdkconfig.h> +#include <gtk/gtk.h> + +#if PLATFORM(X11) +#include "gtk2xtbin.h" +#include <gdk/gdkx.h> +#endif +#ifdef 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; + +void PluginView::updatePluginWidget() const +{ + if (!parent() || !m_isWindowed) + 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()); + + GtkAllocation allocation = { m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height() }; + if (platformPluginWidget()) { + gtk_widget_size_allocate(platformPluginWidget(), &allocation); +#if PLATFORM(X11) + 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::setFocus() +{ + if (platformPluginWidget()) + gtk_widget_grab_focus(platformPluginWidget()); + + Widget::setFocus(); +} + +void PluginView::show() +{ + setSelfVisible(true); + + if (isParentVisible() && platformPluginWidget()) + gtk_widget_show(platformPluginWidget()); + + Widget::show(); +} + +void PluginView::hide() +{ + setSelfVisible(false); + + if (isParentVisible() && platformPluginWidget()) + gtk_widget_hide(platformPluginWidget()); + + Widget::hide(); +} + +void PluginView::paint(GraphicsContext* context, const IntRect& rect) +{ + if (!m_isStarted) { + // Draw the "missing plugin" image + //paintMissingPluginIcon(context, rect); + return; + } + + if (m_isWindowed || context->paintingDisabled()) + return; + + NPEvent npEvent; + /* Need to synthesize Xevents here */ + + m_npWindow.type = NPWindowTypeDrawable; + + ASSERT(parent()->isFrameView()); + + if (m_plugin->pluginFuncs()->event) { + JSC::JSLock::DropAllLocks dropAllLocks(false); + m_plugin->pluginFuncs()->event(m_instance, &npEvent); + } + + setNPWindowRect(frameRect()); +} + +void PluginView::handleKeyboardEvent(KeyboardEvent* event) +{ + NPEvent npEvent; + + /* FIXME: Synthesize an XEvent to pass through */ + + JSC::JSLock::DropAllLocks dropAllLocks(false); + if (!m_plugin->pluginFuncs()->event(m_instance, &npEvent)) + event->setDefaultHandled(); +} + +void PluginView::handleMouseEvent(MouseEvent* event) +{ + NPEvent npEvent; + + if (!m_isWindowed) + return; + + /* FIXME: Synthesize an XEvent to pass through */ + IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(IntPoint(event->pageX(), event->pageY())); + + JSC::JSLock::DropAllLocks dropAllLocks(false); + if (!m_plugin->pluginFuncs()->event(m_instance, &npEvent)) + event->setDefaultHandled(); +} + +void PluginView::setParent(ScrollView* parent) +{ + Widget::setParent(parent); + + if (parent) + init(); + else { + if (!platformPluginWidget()) + return; + } +} + +void PluginView::setNPWindowRect(const IntRect& rect) +{ + if (!m_isStarted || !parent()) + return; + + IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(rect.location()); + m_npWindow.x = p.x(); + m_npWindow.y = p.y(); + + m_npWindow.width = rect.width(); + m_npWindow.height = rect.height(); + + m_npWindow.clipRect.left = 0; + m_npWindow.clipRect.top = 0; + m_npWindow.clipRect.right = rect.width(); + m_npWindow.clipRect.bottom = rect.height(); + + if (m_npWindow.x < 0 || m_npWindow.y < 0 || + m_npWindow.width <= 0 || m_npWindow.height <= 0) + return; + + if (m_plugin->pluginFuncs()->setwindow) { + PluginView::setCurrentPluginView(this); + JSC::JSLock::DropAllLocks dropAllLocks(false); + setCallingPlugin(true); + m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); + setCallingPlugin(false); + PluginView::setCurrentPluginView(0); + + if (!m_isWindowed) + return; + + ASSERT(platformPluginWidget()); + } +} + +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()); + } +} + +void PluginView::stop() +{ + if (!m_isStarted) + return; + + HashSet<RefPtr<PluginStream> > streams = m_streams; + HashSet<RefPtr<PluginStream> >::iterator end = streams.end(); + for (HashSet<RefPtr<PluginStream> >::iterator it = streams.begin(); it != end; ++it) { + (*it)->stop(); + disconnectStream((*it).get()); + } + + ASSERT(m_streams.isEmpty()); + + m_isStarted = false; + JSC::JSLock::DropAllLocks dropAllLocks(false); + + // 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 + + // Destroy the plugin + { + PluginView::setCurrentPluginView(this); + setCallingPlugin(true); + m_plugin->pluginFuncs()->destroy(m_instance, 0); + setCallingPlugin(false); + PluginView::setCurrentPluginView(0); + } + + m_instance->pdata = 0; +} + +static const char* MozillaUserAgent = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0"; + +const char* PluginView::userAgent() +{ + if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent)) + return MozillaUserAgent; + + if (m_userAgent.isNull()) + m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8(); + + return m_userAgent.data(); +} + +const char* PluginView::userAgentStatic() +{ + //FIXME - Lie and say we are Mozilla + return MozillaUserAgent; +} + +NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf) +{ + String filename(buf, len); + + if (filename.startsWith("file:///")) + filename = filename.substring(8); + + // Get file info + 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; +} + +NPError PluginView::getValueStatic(NPNVariable variable, void* value) +{ + switch (variable) { + case NPNVToolkit: +#if PLATFORM(GTK) + *((uint32 *)value) = 2; +#else + *((uint32 *)value) = 0; +#endif + return NPERR_NO_ERROR; + + case NPNVSupportsXEmbedBool: +#if PLATFORM(X11) + *((uint32 *)value) = true; +#else + *((uint32 *)value) = false; +#endif + return NPERR_NO_ERROR; + + case NPNVjavascriptEnabledBool: + *((uint32 *)value) = true; + return NPERR_NO_ERROR; + + default: + return NPERR_GENERIC_ERROR; + } +} + +NPError PluginView::getValue(NPNVariable variable, void* value) +{ + switch (variable) { + case NPNVxDisplay: +#if PLATFORM(X11) + if (m_needsXEmbed) + *(void **)value = (void *)GDK_DISPLAY(); + else + *(void **)value = (void *)GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay; + return NPERR_NO_ERROR; +#else + return NPERR_GENERIC_ERROR; +#endif + +#if PLATFORM(X11) + case NPNVxtAppContext: + if (!m_needsXEmbed) { + *(void **)value = XtDisplayToApplicationContext (GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay); + + return NPERR_NO_ERROR; + } else + return NPERR_GENERIC_ERROR; +#endif + +#if ENABLE(NETSCAPE_PLUGIN_API) + case NPNVWindowNPObject: { + if (m_isJavaScriptPaused) + return NPERR_GENERIC_ERROR; + + NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject(); + + // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> + if (windowScriptObject) + _NPN_RetainObject(windowScriptObject); + + void** v = (void**)value; + *v = windowScriptObject; + + return NPERR_NO_ERROR; + } + + case NPNVPluginElementNPObject: { + if (m_isJavaScriptPaused) + return NPERR_GENERIC_ERROR; + + NPObject* pluginScriptObject = 0; + + if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag)) + pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject(); + + // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> + if (pluginScriptObject) + _NPN_RetainObject(pluginScriptObject); + + void** v = (void**)value; + *v = pluginScriptObject; + + return NPERR_NO_ERROR; + } +#endif + + case NPNVnetscapeWindow: { +#if PLATFORM(X11) + void* w = reinterpret_cast<void*>(value); + *((XID *)w) = GDK_WINDOW_XWINDOW(m_parentFrame->view()->hostWindow()->platformWindow()->window); +#endif +#ifdef GDK_WINDOWING_WIN32 + HGDIOBJ* w = reinterpret_cast<HGDIOBJ*>(value); + *w = GDK_WINDOW_HWND(m_parentFrame->view()->hostWindow()->platformWindow()->window); +#endif + return NPERR_NO_ERROR; + } + + default: + return getValueStatic(variable, value); + } +} + +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); + invalidateRect(r); +} + +void PluginView::forceRedraw() +{ + if (m_isWindowed) + gtk_widget_queue_draw(platformPluginWidget()); + else + gtk_widget_queue_draw(m_parentFrame->view()->hostWindow()->platformWindow()); +} + +PluginView::~PluginView() +{ + stop(); + + deleteAllValues(m_requests); + + freeStringArray(m_paramNames, m_paramCount); + freeStringArray(m_paramValues, m_paramCount); + + m_parentFrame->script()->cleanupScriptObjectsForPlugin(this); + + if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin))) + m_plugin->unload(); +} + +static gboolean +plug_removed_cb(GtkSocket *socket, gpointer) +{ + return TRUE; +} + +void PluginView::init() +{ + if (m_haveInitialized) + return; + m_haveInitialized = true; + + if (!m_plugin) { + ASSERT(m_status == PluginStatusCanNotFindPlugin); + return; + } + + if (!m_plugin->load()) { + m_plugin = 0; + m_status = PluginStatusCanNotLoadPlugin; + return; + } + + if (!start()) { + m_status = PluginStatusCanNotLoadPlugin; + return; + } + + if (m_plugin->pluginFuncs()->getvalue) { + PluginView::setCurrentPluginView(this); + JSC::JSLock::DropAllLocks dropAllLocks(false); + setCallingPlugin(true); + m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); + setCallingPlugin(false); + PluginView::setCurrentPluginView(0); + } + +#if PLATFORM(X11) + if (m_needsXEmbed) { + setPlatformWidget(gtk_socket_new()); + gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->hostWindow()->platformWindow()), platformPluginWidget()); + g_signal_connect(platformPluginWidget(), "plug_removed", G_CALLBACK(plug_removed_cb), NULL); + } else if (m_isWindowed) + setPlatformWidget(gtk_xtbin_new(m_parentFrame->view()->hostWindow()->platformWindow()->window, 0)); +#else + setPlatformWidget(gtk_socket_new()); + gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->hostWindow()->platformWindow()), platformPluginWidget()); +#endif + show(); + + if (m_isWindowed) { + m_npWindow.type = NPWindowTypeWindow; +#if PLATFORM(X11) + NPSetWindowCallbackStruct *ws = new NPSetWindowCallbackStruct(); + + ws->type = 0; + + if (m_needsXEmbed) { + gtk_widget_realize(platformPluginWidget()); + m_npWindow.window = (void*)gtk_socket_get_id(GTK_SOCKET(platformPluginWidget())); + ws->display = GDK_WINDOW_XDISPLAY(platformPluginWidget()->window); + ws->visual = GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(GDK_DRAWABLE(platformPluginWidget()->window))); + ws->depth = gdk_drawable_get_visual(GDK_DRAWABLE(platformPluginWidget()->window))->depth; + ws->colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(GDK_DRAWABLE(platformPluginWidget()->window))); + } 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); + + m_npWindow.ws_info = ws; +#elif defined(GDK_WINDOWING_WIN32) + m_npWindow.window = (void*)GDK_WINDOW_HWND(platformPluginWidget()->window); +#endif + } else { + m_npWindow.type = NPWindowTypeDrawable; + m_npWindow.window = 0; + } + + if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) + setNPWindowRect(frameRect()); + + m_status = PluginStatusLoadedSuccessfully; +} + +} // namespace WebCore diff --git a/WebCore/plugins/gtk/gtk2xtbin.c b/WebCore/plugins/gtk/gtk2xtbin.c new file mode 100644 index 0000000..4247345 --- /dev/null +++ b/WebCore/plugins/gtk/gtk2xtbin.c @@ -0,0 +1,946 @@ +/* -*- 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. + */ + +#undef GTK_DISABLE_DEPRECATED + +#include "xembed.h" +#include "gtk2xtbin.h" +#include <gtk/gtkmain.h> +#include <gtk/gtkprivate.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_destroy (GtkObject *object); +static void gtk_xtbin_shutdown (GtkObject *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) +{ + XEvent event; + 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; +} + +static GSourceFuncs xt_event_funcs = { + xt_event_prepare, + xt_event_check, + xt_event_dispatch, + 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, + }; + 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; + GtkObjectClass *object_class; + + parent_class = gtk_type_class (GTK_TYPE_SOCKET); + + widget_class = GTK_WIDGET_CLASS (klass); + widget_class->realize = gtk_xtbin_realize; + widget_class->unrealize = gtk_xtbin_unrealize; + + object_class = GTK_OBJECT_CLASS (klass); + object_class->destroy = gtk_xtbin_destroy; +} + +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 }; + gint x, y, w, h, d; /* geometry of window */ + +#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 */ + gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d); + allocation.width = w; + allocation.height = h; + gtk_widget_size_allocate (widget, &allocation); + +#ifdef DEBUG_XTBIN + printf("initial allocation %d %d %d %d\n", x, y, w, h); +#endif + + xtbin->width = widget->allocation.width; + xtbin->height = widget->allocation.height; + + /* 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 (GdkWindow *parent_window, String * f) +{ + GtkXtBin *xtbin; + gpointer user_data; + + assert(parent_window != NULL); + xtbin = gtk_type_new (GTK_TYPE_XTBIN); + + if (!xtbin) + return (GtkWidget*)NULL; + + if (f) + fallback = f; + + /* Initialize the Xt toolkit */ + xtbin->parent_window = parent_window; + + xt_client_init(&(xtbin->xtclient), + GDK_VISUAL_XVISUAL(gdk_rgb_get_visual()), + GDK_COLORMAP_XCOLORMAP(gdk_rgb_get_colormap()), + gdk_rgb_get_visual()->depth); + + 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 = + gtk_timeout_add(25, + (GtkFunction)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_REALIZED (xtbin)) + gdk_window_move (GTK_WIDGET (xtbin)->window, 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_UNSET_FLAGS (widget, GTK_VISIBLE); + if (GTK_WIDGET_REALIZED (widget)) { + xt_client_unrealize(&(xtbin->xtclient)); + } + + (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget); +} + +static void +gtk_xtbin_destroy (GtkObject *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); + + gtk_timeout_remove(xt_polling_timer_id); + xt_polling_timer_id = 0; + } + } + + GTK_OBJECT_CLASS(parent_class)->destroy(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; + int errorcode; + + 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) +{ + int errorcode; + + 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/WebCore/plugins/gtk/gtk2xtbin.h b/WebCore/plugins/gtk/gtk2xtbin.h new file mode 100644 index 0000000..2a2b92c --- /dev/null +++ b/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/gtksocket.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 (GdkWindow *parent_window, 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/WebCore/plugins/gtk/xembed.h b/WebCore/plugins/gtk/xembed.h new file mode 100644 index 0000000..dff7be9 --- /dev/null +++ b/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/WebCore/plugins/mac/PluginDataMac.mm b/WebCore/plugins/mac/PluginDataMac.mm new file mode 100644 index 0000000..ec76c37 --- /dev/null +++ b/WebCore/plugins/mac/PluginDataMac.mm @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004 Apple Computer, Inc. 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. + */ + +#import "config.h" +#import "PluginData.h" + +#import "BlockExceptions.h" +#import "Logging.h" +#import "WebCoreViewFactory.h" + +namespace WebCore { + +void PluginData::initPlugins() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + NSArray* plugins = [[WebCoreViewFactory sharedFactory] pluginsInfo]; + for (unsigned int i = 0; i < [plugins count]; ++i) { + PluginInfo* pluginInfo = new PluginInfo; + + id <WebCorePluginInfo> plugin = [plugins objectAtIndex:i]; + + pluginInfo->name = [plugin name]; + pluginInfo->file = [plugin filename]; + pluginInfo->desc = [plugin pluginDescription]; + + NSEnumerator* MIMETypeEnumerator = [plugin MIMETypeEnumerator]; + while (NSString* MIME = [MIMETypeEnumerator nextObject]) { + MimeClassInfo* mime = new MimeClassInfo; + pluginInfo->mimes.append(mime); + mime->type = String(MIME).lower(); + mime->suffixes = [[plugin extensionsForMIMEType:MIME] componentsJoinedByString:@","]; + mime->desc = [plugin descriptionForMIMEType:MIME]; + mime->plugin = pluginInfo; + } + + m_plugins.append(pluginInfo); + } + + END_BLOCK_OBJC_EXCEPTIONS; + + return; +} + +void PluginData::refresh() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + [[WebCoreViewFactory sharedFactory] refreshPlugins]; + END_BLOCK_OBJC_EXCEPTIONS; +} + +} + diff --git a/WebCore/plugins/npapi.cpp b/WebCore/plugins/npapi.cpp index 2f44ba7..05d7c06 100644 --- a/WebCore/plugins/npapi.cpp +++ b/WebCore/plugins/npapi.cpp @@ -26,8 +26,9 @@ #include "config.h" #include "PluginInfoStore.h" +#include "PluginMainThreadScheduler.h" #include "PluginView.h" -#include "npapi.h" // #includes <windows.h> +#include "npruntime_internal.h" using namespace WebCore; @@ -107,10 +108,8 @@ const char* NPN_UserAgent(NPP instance) { PluginView* view = pluginViewForInstance(instance); - // FIXME: Some plug-ins call NPN_UserAgent with a null instance in their NP_initialize function! - // We'd need a way to get a user agent without having a frame around. if (!view) - return 0; + return PluginView::userAgentStatic(); return view->userAgent(); } @@ -137,6 +136,11 @@ void NPN_ForceRedraw(NPP instance) 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); } @@ -157,14 +161,33 @@ void* NPN_GetJavaPeer(NPP instance) return 0; } -void -NPN_PushPopupsEnabledState(NPP instance, NPBool enabled) +void NPN_PushPopupsEnabledState(NPP instance, NPBool enabled) { pluginViewForInstance(instance)->pushPopupsEnabledState(enabled); } -void -NPN_PopPopupsEnabledState(NPP instance) +void NPN_PopPopupsEnabledState(NPP instance) { pluginViewForInstance(instance)->popPopupsEnabledState(); } + +void NPN_PluginThreadAsyncCall(NPP instance, void (*func) (void *), void *userData) +{ + PluginMainThreadScheduler::scheduler().scheduleCall(instance, func, userData); +} + +#ifdef PLUGIN_SCHEDULE_TIMER +uint32 NPN_ScheduleTimer(NPP instance, uint32 interval, NPBool repeat, + void (*timerFunc)(NPP npp, uint32 timerID)) +{ + return pluginViewForInstance(instance)->scheduleTimer(instance, interval, + repeat != 0, timerFunc); +} + +void NPN_UnscheduleTimer(NPP instance, uint32 timerID) +{ + pluginViewForInstance(instance)->unscheduleTimer(instance, timerID); +} +#endif + + diff --git a/WebCore/plugins/npfunctions.h b/WebCore/plugins/npfunctions.h index c847504..21e2e15 100644 --- a/WebCore/plugins/npfunctions.h +++ b/WebCore/plugins/npfunctions.h @@ -22,11 +22,15 @@ * (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 -#ifndef _NPFUNCTIONS_H_ -#define _NPFUNCTIONS_H_ -#include "npruntime_internal.h" +#include "npruntime.h" +#include "npapi.h" +#if defined(ANDROID_PLUGINS) +#include "nativehelper/jni.h" +#endif #ifdef __cplusplus extern "C" { @@ -59,8 +63,12 @@ typedef NPError (*NPN_GetURLProcPtr)(NPP instance, const char* URL, const char* typedef NPError (*NPN_PostURLProcPtr)(NPP instance, const char* URL, const char* window, uint32 len, const char* buf, NPBool file); typedef void* (*NPN_GetJavaEnvProcPtr)(void); typedef void* (*NPN_GetJavaPeerProcPtr)(NPP instance); -typedef void (*NPN_PushPopupsEnabledStateProcPtr)(NPP instance, NPBool enabled); -typedef void (*NPN_PopPopupsEnabledStateProcPtr)(NPP instance); +typedef void (*NPN_PushPopupsEnabledStateProcPtr)(NPP instance, NPBool enabled); +typedef void (*NPN_PopPopupsEnabledStateProcPtr)(NPP instance); +typedef void (*NPN_PluginThreadAsyncCallProcPtr)(NPP npp, void (*func)(void *), void *userData); +typedef uint32 (*NPN_ScheduleTimerProcPtr)(NPP npp, uint32 interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32 timerID)); +typedef void (*NPN_UnscheduleTimerProcPtr)(NPP npp, uint32 timerID); +typedef NPError (*NPN_PopUpContextMenuProcPtr)(NPP instance, NPMenu* menu); typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant); @@ -84,6 +92,7 @@ typedef bool (*NPN_HasMethodProcPtr) (NPP npp, NPObject *npobj, NPIdentifier met 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 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved); typedef NPError (*NPP_DestroyProcPtr)(NPP instance, NPSavedData** save); @@ -98,10 +107,9 @@ typedef int16 (*NPP_HandleEventProcPtr)(NPP instance, void* event); typedef void (*NPP_URLNotifyProcPtr)(NPP instance, const char* URL, NPReason reason, void* notifyData); typedef NPError (*NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value); typedef NPError (*NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value); -typedef EXPORTED_CALLBACK(void, NPP_ShutdownProcPtr)(void); typedef void *(*NPP_GetJavaClassProcPtr)(void); -typedef void* JRIGlobalRef; //not using this right now +typedef void* JRIGlobalRef; //not using this right now typedef struct _NPNetscapeFuncs { uint16 size; @@ -151,6 +159,11 @@ typedef struct _NPNetscapeFuncs { NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate; NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate; NPN_EnumerateProcPtr enumerate; + NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall; + NPN_ConstructProcPtr construct; + NPN_ScheduleTimerProcPtr scheduletimer; + NPN_UnscheduleTimerProcPtr unscheduletimer; + NPN_PopUpContextMenuProcPtr popupcontextmenu; } NPNetscapeFuncs; typedef struct _NPPluginFuncs { @@ -172,19 +185,22 @@ typedef struct _NPPluginFuncs { NPP_SetValueProcPtr setvalue; } NPPluginFuncs; -#if defined(XP_WIN) -typedef EXPORTED_CALLBACK(NPError, NP_InitializeFuncPtr)(NPNetscapeFuncs*); typedef EXPORTED_CALLBACK(NPError, NP_GetEntryPointsFuncPtr)(NPPluginFuncs*); -#endif +typedef EXPORTED_CALLBACK(void, NPP_ShutdownProcPtr)(void); #if defined(XP_MACOSX) -typedef void (*BP_CreatePluginMIMETypesPreferencesFuncPtr)(void); +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, jobject application_context); +typedef EXPORTED_CALLBACK(char*, NP_GetMIMEDescriptionFuncPtr)(void); +#else +typedef EXPORTED_CALLBACK(NPError, NP_InitializeFuncPtr)(NPNetscapeFuncs*); #endif #ifdef __cplusplus diff --git a/WebCore/plugins/qt/PluginDataQt.cpp b/WebCore/plugins/qt/PluginDataQt.cpp new file mode 100644 index 0000000..13f1442 --- /dev/null +++ b/WebCore/plugins/qt/PluginDataQt.cpp @@ -0,0 +1,108 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + 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" + +#if QT_VERSION >= 0x040400 +#include "ChromeClientQt.h" +#include "Page.h" +#include <qwebpage.h> +#include <qwebpluginfactory.h> +#endif + +namespace WebCore { + +void PluginData::initPlugins() +{ +#if QT_VERSION >= 0x040400 + QWebPage* webPage = static_cast<ChromeClientQt*>(m_page->chrome()->client())->m_webPage; + QWebPluginFactory* factory = webPage->pluginFactory(); + if (factory) { + + QList<QWebPluginFactory::Plugin> qplugins = factory->plugins(); + for (int i = 0; i < qplugins.count(); ++i) { + const QWebPluginFactory::Plugin& qplugin = qplugins.at(i); + + PluginInfo* info = new PluginInfo; + info->name = qplugin.name; + info->desc = qplugin.description; + + for (int j = 0; j < qplugin.mimeTypes.count(); ++j) { + const QWebPluginFactory::MimeType& mimeType = qplugin.mimeTypes.at(j); + + MimeClassInfo* mimeInfo = new MimeClassInfo; + mimeInfo->type = mimeType.name; + mimeInfo->desc = mimeType.description; + mimeInfo->suffixes = mimeType.fileExtensions.join("; "); + + info->mimes.append(mimeInfo); + } + + m_plugins.append(info); + } + } +#endif + + PluginDatabase *db = PluginDatabase::installedPlugins(); + const Vector<PluginPackage*> &plugins = db->plugins(); + + for (unsigned int i = 0; i < plugins.size(); ++i) { + PluginInfo* info = new PluginInfo; + PluginPackage* package = plugins[i]; + + info->name = package->name(); + info->file = package->fileName(); + info->desc = package->description(); + + const MIMEToDescriptionsMap& mimeToDescriptions = package->mimeToDescriptions(); + MIMEToDescriptionsMap::const_iterator end = mimeToDescriptions.end(); + for (MIMEToDescriptionsMap::const_iterator it = mimeToDescriptions.begin(); it != end; ++it) { + MimeClassInfo* mime = new MimeClassInfo; + info->mimes.append(mime); + + mime->type = it->first; + mime->desc = it->second; + mime->plugin = info; + + Vector<String> extensions = package->mimeToExtensions().get(mime->type); + + for (unsigned i = 0; i < extensions.size(); i++) { + if (i > 0) + mime->suffixes += ","; + + mime->suffixes += extensions[i]; + } + } + + m_plugins.append(info); + } +} + +void PluginData::refresh() +{ + PluginDatabase *db = PluginDatabase::installedPlugins(); + db->refresh(); +} + +}; diff --git a/WebCore/plugins/qt/PluginPackageQt.cpp b/WebCore/plugins/qt/PluginPackageQt.cpp new file mode 100644 index 0000000..423c4e1 --- /dev/null +++ b/WebCore/plugins/qt/PluginPackageQt.cpp @@ -0,0 +1,220 @@ +/* + * 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 "CString.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "npruntime_impl.h" +#include "PluginDatabase.h" +#include "PluginDebug.h" + +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); + } + +} + +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; + + String s = gm(); + Vector<String> types; + s.split(UChar(';'), false, types); + for (int 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]); + } + } + + return true; +} + +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(Plugin, "%s not loaded", m_path.utf8().data()); + 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); + + 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; + +#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; +} + +unsigned PluginPackage::hash() const +{ + unsigned hashCodes[2] = { + m_path.impl()->hash(), + m_lastModified + }; + + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 2 * sizeof(unsigned) / sizeof(UChar)); +} + +bool PluginPackage::equal(const PluginPackage& a, const PluginPackage& b) +{ + return a.m_description == b.m_description; +} + +int PluginPackage::compareFileVersion(const PlatformModuleVersion& compareVersion) const +{ + // return -1, 0, or 1 if plug-in version is less than, equal to, or greater than + // the passed version + if (m_moduleVersion != compareVersion) + return m_moduleVersion > compareVersion ? 1 : -1; + return 0; +} + +} diff --git a/WebCore/plugins/qt/PluginViewQt.cpp b/WebCore/plugins/qt/PluginViewQt.cpp new file mode 100644 index 0000000..819fd36 --- /dev/null +++ b/WebCore/plugins/qt/PluginViewQt.cpp @@ -0,0 +1,483 @@ +/* + * 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 "PluginView.h" + +#include <QWidget> +#include <QX11EmbedContainer> +#include <QX11Info> + +#include "NotImplemented.h" +#include "PluginDebug.h" +#include "PluginPackage.h" +#include "npruntime_impl.h" +#include "runtime.h" +#include "runtime_root.h" +#include <runtime/JSLock.h> +#include <runtime/JSValue.h> +#include "JSDOMBinding.h" +#include "ScriptController.h" + +#include "Document.h" +#include "DocumentLoader.h" +#include "Element.h" +#include "FrameLoader.h" +#include "FrameLoadRequest.h" +#include "FrameTree.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "HTMLNames.h" +#include "HTMLPlugInElement.h" +#include "KeyboardEvent.h" +#include "MouseEvent.h" +#include "Page.h" +#include "PlatformMouseEvent.h" +#include "RenderLayer.h" +#include "Settings.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; + +void PluginView::updatePluginWidget() const +{ + if (!parent() || !m_isWindowed) + return; + + ASSERT(parent()->isFrameView()); + FrameView* frameView = static_cast<FrameView*>(parent()); + + IntRect oldWindowRect = m_windowRect; + IntRect oldClipRect = m_clipRect; + + m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); + m_clipRect = windowClipRect(); + m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); + + if (platformPluginWidget()) { + platformPluginWidget()->move(m_windowRect.x(), m_windowRect.y()); + platformPluginWidget()->resize(m_windowRect.width(), m_windowRect.height()); + platformPluginWidget()->setMask(QRegion(m_clipRect.x(), m_clipRect.y(), m_clipRect.width(), m_clipRect.height())); + } +} + +void PluginView::setFocus() +{ + if (platformPluginWidget()) + platformPluginWidget()->setFocus(Qt::OtherFocusReason); + else + Widget::setFocus(); +} + +void PluginView::show() +{ + setSelfVisible(true); + + if (isParentVisible() && platformPluginWidget()) + platformPluginWidget()->setVisible(true); + + Widget::show(); +} + +void PluginView::hide() +{ + setSelfVisible(false); + + if (isParentVisible() && platformPluginWidget()) + platformPluginWidget()->setVisible(false); + + Widget::hide(); +} + +void PluginView::paint(GraphicsContext* context, const IntRect& rect) +{ + if (!m_isStarted) { + // Draw the "missing plugin" image + //paintMissingPluginIcon(context, rect); + return; + } + + if (m_isWindowed || context->paintingDisabled()) + return; + + notImplemented(); +} + +void PluginView::handleKeyboardEvent(KeyboardEvent* event) +{ + notImplemented(); +} + +void PluginView::handleMouseEvent(MouseEvent* event) +{ + notImplemented(); +} + +void PluginView::setParent(ScrollView* parent) +{ + Widget::setParent(parent); + + if (parent) + init(); + else { + if (!platformPluginWidget()) + return; + } +} + +void PluginView::setNPWindowRect(const IntRect& rect) +{ + if (!m_isStarted || !parent()) + return; + + IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(rect.location()); + m_npWindow.x = p.x(); + m_npWindow.y = p.y(); + + m_npWindow.width = rect.width(); + m_npWindow.height = rect.height(); + + m_npWindow.clipRect.left = 0; + m_npWindow.clipRect.top = 0; + m_npWindow.clipRect.right = rect.width(); + m_npWindow.clipRect.bottom = rect.height(); + + if (m_npWindow.x < 0 || m_npWindow.y < 0 || + m_npWindow.width <= 0 || m_npWindow.height <= 0) + return; + + if (m_plugin->pluginFuncs()->setwindow) { + PluginView::setCurrentPluginView(this); + JSC::JSLock::DropAllLocks dropAllLocks(false); + setCallingPlugin(true); + m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); + setCallingPlugin(false); + PluginView::setCurrentPluginView(0); + + if (!m_isWindowed) + return; + + ASSERT(platformPluginWidget()); + } +} + +void PluginView::setParentVisible(bool visible) +{ + if (isParentVisible() == visible) + return; + + Widget::setParentVisible(visible); + + if (isSelfVisible() && platformPluginWidget()) + platformPluginWidget()->setVisible(visible); +} + +void PluginView::stop() +{ + if (!m_isStarted) + return; + + HashSet<RefPtr<PluginStream> > streams = m_streams; + HashSet<RefPtr<PluginStream> >::iterator end = streams.end(); + for (HashSet<RefPtr<PluginStream> >::iterator it = streams.begin(); it != end; ++it) { + (*it)->stop(); + disconnectStream((*it).get()); + } + + ASSERT(m_streams.isEmpty()); + + m_isStarted = false; + + JSC::JSLock::DropAllLocks dropAllLocks(false); + + // Clear the window + m_npWindow.window = 0; + delete (NPSetWindowCallbackStruct *)m_npWindow.ws_info; + m_npWindow.ws_info = 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); + } + + // Destroy the plugin + { + PluginView::setCurrentPluginView(this); + setCallingPlugin(true); + m_plugin->pluginFuncs()->destroy(m_instance, 0); + setCallingPlugin(false); + PluginView::setCurrentPluginView(0); + } + + m_instance->pdata = 0; +} + +static const char* MozillaUserAgent = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0"; + +const char* PluginView::userAgent() +{ + if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent)) + return MozillaUserAgent; + + if (m_userAgent.isNull()) + m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8(); + + return m_userAgent.data(); +} + +const char* PluginView::userAgentStatic() +{ + //FIXME - Just say we are Mozilla + return MozillaUserAgent; +} + +NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf) +{ + String filename(buf, len); + + if (filename.startsWith("file:///")) + filename = filename.substring(8); + + if (!fileExists(filename)) + 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; +} + +NPError PluginView::getValueStatic(NPNVariable variable, void* value) +{ + switch (variable) { + case NPNVToolkit: + *((uint32 *)value) = 0; + return NPERR_NO_ERROR; + + case NPNVSupportsXEmbedBool: + *((uint32 *)value) = true; + return NPERR_NO_ERROR; + + case NPNVjavascriptEnabledBool: + *((uint32 *)value) = true; + return NPERR_NO_ERROR; + + default: + return NPERR_GENERIC_ERROR; + } +} + +NPError PluginView::getValue(NPNVariable variable, void* value) +{ + switch (variable) { + case NPNVxDisplay: + if (platformPluginWidget()) + *(void **)value = platformPluginWidget()->x11Info().display(); + else + *(void **)value = m_parentFrame->view()->hostWindow()->platformWindow()->x11Info().display(); + return NPERR_NO_ERROR; + + case NPNVxtAppContext: + return NPERR_GENERIC_ERROR; + +#if ENABLE(NETSCAPE_PLUGIN_API) + case NPNVWindowNPObject: { + if (m_isJavaScriptPaused) + return NPERR_GENERIC_ERROR; + + NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject(); + + // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> + if (windowScriptObject) + _NPN_RetainObject(windowScriptObject); + + void** v = (void**)value; + *v = windowScriptObject; + + return NPERR_NO_ERROR; + } + + case NPNVPluginElementNPObject: { + if (m_isJavaScriptPaused) + return NPERR_GENERIC_ERROR; + + NPObject* pluginScriptObject = 0; + + if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag)) + pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject(); + + // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> + if (pluginScriptObject) + _NPN_RetainObject(pluginScriptObject); + + void** v = (void**)value; + *v = pluginScriptObject; + + return NPERR_NO_ERROR; + } +#endif + + case NPNVnetscapeWindow: { + void* w = reinterpret_cast<void*>(value); + *((XID *)w) = m_parentFrame->view()->hostWindow()->platformWindow()->winId(); + return NPERR_NO_ERROR; + } + + default: + return getValueStatic(variable, value); + } +} + +void PluginView::invalidateRect(const IntRect& rect) +{ + if (platformWidget()) { + platformWidget()->update(rect); + return; + } + + invalidateWindowlessPluginRect(rect); +} + +void PluginView::invalidateRect(NPRect* rect) +{ + notImplemented(); +} + +void PluginView::invalidateRegion(NPRegion region) +{ + notImplemented(); +} + +void PluginView::forceRedraw() +{ + notImplemented(); +} + +PluginView::~PluginView() +{ + stop(); + + deleteAllValues(m_requests); + + freeStringArray(m_paramNames, m_paramCount); + freeStringArray(m_paramValues, m_paramCount); + + m_parentFrame->script()->cleanupScriptObjectsForPlugin(this); + + if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin))) + m_plugin->unload(); + + delete platformPluginWidget(); +} + +void PluginView::init() +{ + if (m_haveInitialized) + return; + m_haveInitialized = true; + + if (!m_plugin) { + ASSERT(m_status == PluginStatusCanNotFindPlugin); + return; + } + + if (!m_plugin->load()) { + m_plugin = 0; + m_status = PluginStatusCanNotLoadPlugin; + return; + } + + if (!start()) { + m_status = PluginStatusCanNotLoadPlugin; + return; + } + + if (m_plugin->pluginFuncs()->getvalue) { + PluginView::setCurrentPluginView(this); + JSC::JSLock::DropAllLocks dropAllLocks(false); + setCallingPlugin(true); + m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); + setCallingPlugin(false); + PluginView::setCurrentPluginView(0); + } + + if (m_needsXEmbed) { + setPlatformWidget(new QX11EmbedContainer(m_parentFrame->view()->hostWindow()->platformWindow())); + setIsNPAPIPlugin(true); + } else { + notImplemented(); + m_status = PluginStatusCanNotLoadPlugin; + return; + } + show (); + + NPSetWindowCallbackStruct *wsi = new NPSetWindowCallbackStruct(); + + wsi->type = 0; + + wsi->display = platformPluginWidget()->x11Info().display(); + wsi->visual = (Visual*)platformPluginWidget()->x11Info().visual(); + wsi->depth = platformPluginWidget()->x11Info().depth(); + wsi->colormap = platformPluginWidget()->x11Info().colormap(); + m_npWindow.ws_info = wsi; + + m_npWindow.type = NPWindowTypeWindow; + m_npWindow.window = (void*)platformPluginWidget()->winId(); + + if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) + setNPWindowRect(frameRect()); + + m_status = PluginStatusLoadedSuccessfully; +} + +} // namespace WebCore diff --git a/WebCore/plugins/win/PluginDataWin.cpp b/WebCore/plugins/win/PluginDataWin.cpp new file mode 100644 index 0000000..4ec4b6d --- /dev/null +++ b/WebCore/plugins/win/PluginDataWin.cpp @@ -0,0 +1,72 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "PluginData.h" + +#include "PluginDatabase.h" +#include "PluginPackage.h" + +namespace WebCore { + +void PluginData::initPlugins() +{ + PluginDatabase *db = PluginDatabase::installedPlugins(); + const Vector<PluginPackage*> &plugins = db->plugins(); + + for (unsigned int i = 0; i < plugins.size(); ++i) { + PluginInfo* info = new PluginInfo; + PluginPackage* package = plugins[i]; + + info->name = package->name(); + info->file = package->fileName(); + info->desc = package->description(); + + const MIMEToDescriptionsMap& mimeToDescriptions = package->mimeToDescriptions(); + MIMEToDescriptionsMap::const_iterator end = mimeToDescriptions.end(); + for (MIMEToDescriptionsMap::const_iterator it = mimeToDescriptions.begin(); it != end; ++it) { + MimeClassInfo* mime = new MimeClassInfo; + info->mimes.append(mime); + + mime->type = it->first; + mime->desc = it->second; + mime->plugin = info; + + Vector<String> extensions = package->mimeToExtensions().get(mime->type); + + for (unsigned i = 0; i < extensions.size(); i++) { + if (i > 0) + mime->suffixes += ","; + + mime->suffixes += extensions[i]; + } + } + + m_plugins.append(info); + } +} + +void PluginData::refresh() +{ + PluginDatabase *db = PluginDatabase::installedPlugins(); + db->refresh(); +} + +}; diff --git a/WebCore/plugins/win/PluginDatabaseWin.cpp b/WebCore/plugins/win/PluginDatabaseWin.cpp index be8a253..c59f133 100644 --- a/WebCore/plugins/win/PluginDatabaseWin.cpp +++ b/WebCore/plugins/win/PluginDatabaseWin.cpp @@ -1,5 +1,6 @@ /* * 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 @@ -26,100 +27,19 @@ #include "config.h" #include "PluginDatabase.h" -#include "PluginPackage.h" -#include "PluginView.h" #include "Frame.h" +#include "KURL.h" +#include "PluginPackage.h" #include <windows.h> #include <shlwapi.h> -namespace WebCore { - -PluginDatabase* PluginDatabase::installedPlugins() -{ - static PluginDatabase* plugins = 0; - - if (!plugins) { - plugins = new PluginDatabase; - plugins->setPluginPaths(PluginDatabase::defaultPluginPaths()); - plugins->refresh(); - } - - return plugins; -} - -void PluginDatabase::addExtraPluginPath(const String& path) -{ - m_pluginPaths.append(path); - refresh(); -} - -bool PluginDatabase::refresh() -{ - PluginSet newPlugins; - - bool pluginSetChanged = false; - - // Create a new set of plugins - newPlugins = getPluginsInPaths(); - - if (!m_plugins.isEmpty()) { - m_registeredMIMETypes.clear(); - - PluginSet pluginsToUnload = m_plugins; +#if COMPILER(MINGW) +#define _countof(x) (sizeof(x)/sizeof(x[0])) +#endif - PluginSet::const_iterator end = newPlugins.end(); - for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it) - pluginsToUnload.remove(*it); - - end = m_plugins.end(); - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) - newPlugins.remove(*it); - - // Unload plugins - end = pluginsToUnload.end(); - for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it) - m_plugins.remove(*it); - - // Add new plugins - end = newPlugins.end(); - for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it) - m_plugins.add(*it); - - pluginSetChanged = !pluginsToUnload.isEmpty() || !newPlugins.isEmpty(); - } else { - m_plugins = newPlugins; - PluginSet::const_iterator end = newPlugins.end(); - for (PluginSet::const_iterator it = newPlugins.begin(); it != end; ++it) - m_plugins.add(*it); - - pluginSetChanged = !newPlugins.isEmpty(); - } - - // Register plug-in MIME types - PluginSet::const_iterator end = m_plugins.end(); - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { - // Get MIME types - MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end(); - for (MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin(); map_it != map_end; ++map_it) { - m_registeredMIMETypes.add(map_it->first); - } - } - - return pluginSetChanged; -} - -Vector<PluginPackage*> PluginDatabase::plugins() const -{ - Vector<PluginPackage*> result; - - PluginSet::const_iterator end = m_plugins.end(); - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) - result.append((*it).get()); - - return result; -} +namespace WebCore { -static inline void addPluginsFromRegistry(HKEY rootKey, PluginSet& plugins) +static inline void addPluginPathsFromRegistry(HKEY rootKey, HashSet<String>& paths) { HKEY key; HRESULT result = RegOpenKeyExW(rootKey, L"Software\\MozillaPlugins", 0, KEY_ENUMERATE_SUB_KEYS, &key); @@ -146,33 +66,25 @@ static inline void addPluginsFromRegistry(HKEY rootKey, PluginSet& plugins) if (result != ERROR_SUCCESS || type != REG_SZ) continue; - WIN32_FILE_ATTRIBUTE_DATA attributes; - if (GetFileAttributesEx(pathStr, GetFileExInfoStandard, &attributes) == 0) - continue; - - PluginPackage* package = PluginPackage::createPackage(String(pathStr, pathStrSize / sizeof(WCHAR) - 1), attributes.ftLastWriteTime); - - if (package) - plugins.add(package); + paths.add(String(pathStr, pathStrSize / sizeof(WCHAR) - 1)); } RegCloseKey(key); } -PluginSet PluginDatabase::getPluginsInPaths() const +void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const { // FIXME: This should be a case insensitive set. HashSet<String> uniqueFilenames; - PluginSet plugins; HANDLE hFind = INVALID_HANDLE_VALUE; WIN32_FIND_DATAW findFileData; - PluginPackage* oldWMPPlugin = 0; - PluginPackage* newWMPPlugin = 0; + String oldWMPPluginPath; + String newWMPPluginPath; - Vector<String>::const_iterator end = m_pluginPaths.end(); - for (Vector<String>::const_iterator it = m_pluginPaths.begin(); it != end; ++it) { + 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); @@ -192,32 +104,26 @@ PluginSet PluginDatabase::getPluginsInPaths() const String fullPath = *it + "\\" + filename; if (!uniqueFilenames.add(fullPath).second) continue; - - PluginPackage* pluginPackage = PluginPackage::createPackage(fullPath, findFileData.ftLastWriteTime); - if (pluginPackage) { - plugins.add(pluginPackage); + paths.add(fullPath); - if (equalIgnoringCase(filename, "npdsplay.dll")) - oldWMPPlugin = pluginPackage; - else if (equalIgnoringCase(filename, "np-mswmp.dll")) - newWMPPlugin = pluginPackage; - } + if (equalIgnoringCase(filename, "npdsplay.dll")) + oldWMPPluginPath = fullPath; + else if (equalIgnoringCase(filename, "np-mswmp.dll")) + newWMPPluginPath = fullPath; } while (FindNextFileW(hFind, &findFileData) != 0); FindClose(hFind); } - addPluginsFromRegistry(HKEY_LOCAL_MACHINE, plugins); - addPluginsFromRegistry(HKEY_CURRENT_USER, plugins); + 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 (oldWMPPlugin && newWMPPlugin) - plugins.remove(oldWMPPlugin); - - return plugins; + if (!oldWMPPluginPath.isEmpty() && !newWMPPluginPath.isEmpty()) + paths.remove(oldWMPPluginPath); } static inline Vector<int> parseVersionString(const String& versionString) @@ -258,7 +164,7 @@ static inline bool compareVersions(const Vector<int>& versionA, const Vector<int return false; } -static inline void addMozillaPluginPaths(Vector<String>& paths) +static inline void addMozillaPluginDirectories(Vector<String>& directories) { // Enumerate all Mozilla plugin directories in the registry HKEY key; @@ -284,15 +190,15 @@ static inline void addMozillaPluginPaths(Vector<String>& paths) result = RegOpenKeyEx(key, extensionsPath.charactersWithNullTermination(), 0, KEY_READ, &extensionsKey); if (result == ERROR_SUCCESS) { - // Now get the plugins path - WCHAR pluginsPathStr[_MAX_PATH]; - DWORD pluginsPathSize = sizeof(pluginsPathStr); + // Now get the plugins directory + WCHAR pluginsDirectoryStr[_MAX_PATH]; + DWORD pluginsDirectorySize = sizeof(pluginsDirectoryStr); DWORD type; - result = RegQueryValueEx(extensionsKey, TEXT("Plugins"), 0, &type, (LPBYTE)&pluginsPathStr, &pluginsPathSize); + result = RegQueryValueEx(extensionsKey, TEXT("Plugins"), 0, &type, (LPBYTE)&pluginsDirectoryStr, &pluginsDirectorySize); if (result == ERROR_SUCCESS && type == REG_SZ) - paths.append(String(pluginsPathStr, pluginsPathSize / sizeof(WCHAR) - 1)); + directories.append(String(pluginsDirectoryStr, pluginsDirectorySize / sizeof(WCHAR) - 1)); RegCloseKey(extensionsKey); } @@ -302,14 +208,14 @@ static inline void addMozillaPluginPaths(Vector<String>& paths) } } -static inline void addWindowsMediaPlayerPluginPath(Vector<String>& paths) +static inline void addWindowsMediaPlayerPluginDirectory(Vector<String>& directories) { // The new WMP Firefox plugin is installed in \PFiles\Plugins if it can't find any Firefox installs WCHAR pluginDirectoryStr[_MAX_PATH + 1]; DWORD pluginDirectorySize = ::ExpandEnvironmentStringsW(TEXT("%SYSTEMDRIVE%\\PFiles\\Plugins"), pluginDirectoryStr, _countof(pluginDirectoryStr)); if (pluginDirectorySize > 0 && pluginDirectorySize <= _countof(pluginDirectoryStr)) - paths.append(String(pluginDirectoryStr, pluginDirectorySize - 1)); + directories.append(String(pluginDirectoryStr, pluginDirectorySize - 1)); DWORD type; WCHAR installationDirectoryStr[_MAX_PATH]; @@ -318,10 +224,10 @@ static inline void addWindowsMediaPlayerPluginPath(Vector<String>& paths) HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\MediaPlayer"), TEXT("Installation Directory"), &type, (LPBYTE)&installationDirectoryStr, &installationDirectorySize); if (result == ERROR_SUCCESS && type == REG_SZ) - paths.append(String(installationDirectoryStr, installationDirectorySize / sizeof(WCHAR) - 1)); + directories.append(String(installationDirectoryStr, installationDirectorySize / sizeof(WCHAR) - 1)); } -static inline void addQuickTimePluginPath(Vector<String>& paths) +static inline void addQuickTimePluginDirectory(Vector<String>& directories) { DWORD type; WCHAR installationDirectoryStr[_MAX_PATH]; @@ -331,11 +237,11 @@ static inline void addQuickTimePluginPath(Vector<String>& paths) if (result == ERROR_SUCCESS && type == REG_SZ) { String pluginDir = String(installationDirectoryStr, installationDirectorySize / sizeof(WCHAR) - 1) + "\\plugins"; - paths.append(pluginDir); + directories.append(pluginDir); } } -static inline void addAdobeAcrobatPluginPath(Vector<String>& paths) +static inline void addAdobeAcrobatPluginDirectory(Vector<String>& directories) { HKEY key; HRESULT result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Adobe\\Acrobat Reader"), 0, KEY_READ, &key); @@ -372,22 +278,22 @@ static inline void addAdobeAcrobatPluginPath(Vector<String>& paths) result = SHGetValue(HKEY_LOCAL_MACHINE, acrobatPluginKeyPath.charactersWithNullTermination(), 0, &type, (LPBYTE)acrobatInstallPathStr, &acrobatInstallPathSize); if (result == ERROR_SUCCESS) { - String acrobatPluginPath = String(acrobatInstallPathStr, acrobatInstallPathSize / sizeof(WCHAR) - 1) + "\\browser"; - paths.append(acrobatPluginPath); + String acrobatPluginDirectory = String(acrobatInstallPathStr, acrobatInstallPathSize / sizeof(WCHAR) - 1) + "\\browser"; + directories.append(acrobatPluginDirectory); } } RegCloseKey(key); } -static inline String safariPluginsPath() +static inline String safariPluginsDirectory() { WCHAR moduleFileNameStr[_MAX_PATH]; - static String pluginsPath; - static bool cachedPluginPath = false; + static String pluginsDirectory; + static bool cachedPluginDirectory = false; - if (!cachedPluginPath) { - cachedPluginPath = true; + if (!cachedPluginDirectory) { + cachedPluginDirectory = true; int moduleFileNameLen = GetModuleFileName(0, moduleFileNameStr, _MAX_PATH); @@ -397,13 +303,13 @@ static inline String safariPluginsPath() if (!PathRemoveFileSpec(moduleFileNameStr)) goto exit; - pluginsPath = String(moduleFileNameStr) + "\\Plugins"; + pluginsDirectory = String(moduleFileNameStr) + "\\Plugins"; } exit: - return pluginsPath; + return pluginsDirectory; } -static inline void addMacromediaPluginPaths(Vector<String>& paths) +static inline void addMacromediaPluginDirectories(Vector<String>& directories) { WCHAR systemDirectoryStr[MAX_PATH]; @@ -413,128 +319,36 @@ static inline void addMacromediaPluginPaths(Vector<String>& paths) WCHAR macromediaDirectoryStr[MAX_PATH]; PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Flash")); - paths.append(macromediaDirectoryStr); + directories.append(macromediaDirectoryStr); PathCombine(macromediaDirectoryStr, systemDirectoryStr, TEXT("macromed\\Shockwave 10")); - paths.append(macromediaDirectoryStr); + directories.append(macromediaDirectoryStr); } -Vector<String> PluginDatabase::defaultPluginPaths() +Vector<String> PluginDatabase::defaultPluginDirectories() { - Vector<String> paths; - String ourPath = safariPluginsPath(); - - if (!ourPath.isNull()) - paths.append(ourPath); - addQuickTimePluginPath(paths); - addAdobeAcrobatPluginPath(paths); - addMozillaPluginPaths(paths); - addWindowsMediaPlayerPluginPath(paths); - addMacromediaPluginPaths(paths); - - return paths; + Vector<String> directories; + String ourDirectory = safariPluginsDirectory(); + + if (!ourDirectory.isNull()) + directories.append(ourDirectory); + addQuickTimePluginDirectory(directories); + addAdobeAcrobatPluginDirectory(directories); + addMozillaPluginDirectories(directories); + addWindowsMediaPlayerPluginDirectory(directories); + addMacromediaPluginDirectories(directories); + + return directories; } -bool PluginDatabase::isMIMETypeRegistered(const String& mimeType) +bool PluginDatabase::isPreferredPluginDirectory(const String& directory) { - 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)); -} + String ourDirectory = safariPluginsDirectory(); -PluginPackage* PluginDatabase::pluginForMIMEType(const String& mimeType) -{ - if (mimeType.isEmpty()) - return 0; - - String key = mimeType.lower(); - String ourPath = safariPluginsPath(); - PluginPackage* plugin = 0; - PluginSet::const_iterator end = m_plugins.end(); - - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { - if ((*it)->mimeToDescriptions().contains(key)) { - plugin = (*it).get(); - // prefer plugins in our own plugins directory - if (plugin->parentDirectory() == ourPath) - break; - } - } - - return plugin; -} + if (!ourDirectory.isNull() && !directory.isNull()) + return ourDirectory == directory; -String PluginDatabase::MIMETypeForExtension(const String& extension) const -{ - if (extension.isEmpty()) - return String(); - - PluginSet::const_iterator end = m_plugins.end(); - String ourPath = safariPluginsPath(); - String mimeType; - PluginPackage* plugin = 0; - - for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { - MIMEToExtensionsMap::const_iterator mime_end = (*it)->mimeToExtensions().end(); - - for (MIMEToExtensionsMap::const_iterator mime_it = (*it)->mimeToExtensions().begin(); mime_it != mime_end; ++mime_it) { - const Vector<String>& extensions = mime_it->second; - for (unsigned i = 0; i < extensions.size(); i++) { - if (equalIgnoringCase(extensions[i], extension)) { - mimeType = mime_it->first; - plugin = (*it).get(); - // prefer plugins in our own plugins directory - if (plugin->parentDirectory() == ourPath) - break; - } - } - } - } - - return mimeType; -} - -PluginPackage* PluginDatabase::findPlugin(const KURL& url, String& mimeType) -{ - PluginPackage* plugin = pluginForMIMEType(mimeType); - String filename = url.string(); - - if (!plugin) { - String filename = url.lastPathComponent(); - if (!filename.endsWith("/")) { - int extensionPos = filename.reverseFind('.'); - if (extensionPos != -1) { - String extension = filename.substring(extensionPos + 1); - - mimeType = MIMETypeForExtension(extension); - plugin = pluginForMIMEType(mimeType); - } - } - } - - // FIXME: if no plugin could be found, query Windows for the mime type - // corresponding to the extension. - - return plugin; -} - -PluginView* PluginDatabase::createPluginView(Frame* parentFrame, const IntSize& size, Element* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually) -{ - // if we fail to find a plugin for this MIME type, findPlugin will search for - // a plugin by the file extension and update the MIME type, so pass a mutable String - String mimeTypeCopy = mimeType; - PluginPackage* plugin = findPlugin(url, mimeTypeCopy); - - // No plugin was found, try refreshing the database and searching again - if (!plugin && refresh()) { - mimeTypeCopy = mimeType; - plugin = findPlugin(url, mimeTypeCopy); - } - - return new PluginView(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually); + return false; } } diff --git a/WebCore/plugins/win/PluginMessageThrottlerWin.cpp b/WebCore/plugins/win/PluginMessageThrottlerWin.cpp new file mode 100644 index 0000000..27bf5b9 --- /dev/null +++ b/WebCore/plugins/win/PluginMessageThrottlerWin.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PluginMessageThrottlerWin.h" + +#include "PluginView.h" +#include <wtf/ASCIICType.h> + +using namespace WTF; + +namespace WebCore { + +static const double MessageThrottleTimeInterval = 0.001; + +PluginMessageThrottlerWin::PluginMessageThrottlerWin(PluginView* pluginView) + : m_back(0), m_front(0) + , m_pluginView(pluginView) + , m_messageThrottleTimer(this, &PluginMessageThrottlerWin::messageThrottleTimerFired) +{ + // Initialize the free list with our inline messages + for (unsigned i = 0; i < NumInlineMessages - 1; i++) + m_inlineMessages[i].next = &m_inlineMessages[i + 1]; + m_inlineMessages[NumInlineMessages - 1].next = 0; + m_freeInlineMessages = &m_inlineMessages[0]; +} + +PluginMessageThrottlerWin::~PluginMessageThrottlerWin() +{ + PluginMessage* next; + + for (PluginMessage* message = m_front; message; message = next) { + next = message->next; + freeMessage(message); + } +} + +void PluginMessageThrottlerWin::appendMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + PluginMessage* message = allocateMessage(); + + message->hWnd = hWnd; + message->msg = msg; + message->wParam = wParam; + message->lParam = lParam; + message->next = 0; + + if (m_back) + m_back->next = message; + m_back = message; + if (!m_front) + m_front = message; + + if (!m_messageThrottleTimer.isActive()) + m_messageThrottleTimer.startOneShot(MessageThrottleTimeInterval); +} + +void PluginMessageThrottlerWin::messageThrottleTimerFired(Timer<PluginMessageThrottlerWin>*) +{ + PluginMessage* message = m_front; + m_front = m_front->next; + if (message == m_back) + m_back = 0; + + ::CallWindowProc(m_pluginView->pluginWndProc(), message->hWnd, message->msg, message->wParam, message->lParam); + + freeMessage(message); + + if (m_front) + m_messageThrottleTimer.startOneShot(MessageThrottleTimeInterval); +} + +PluginMessage* PluginMessageThrottlerWin::allocateMessage() +{ + PluginMessage *message; + + if (m_freeInlineMessages) { + message = m_freeInlineMessages; + m_freeInlineMessages = message->next; + } else + message = new PluginMessage; + + return message; +} + +bool PluginMessageThrottlerWin::isInlineMessage(PluginMessage* message) +{ + return message >= &m_inlineMessages[0] && message <= &m_inlineMessages[NumInlineMessages - 1]; +} + +void PluginMessageThrottlerWin::freeMessage(PluginMessage* message) +{ + if (isInlineMessage(message)) { + message->next = m_freeInlineMessages; + m_freeInlineMessages = message; + } else + delete message; +} + +} // namespace WebCore diff --git a/WebCore/plugins/win/PluginMessageThrottlerWin.h b/WebCore/plugins/win/PluginMessageThrottlerWin.h new file mode 100644 index 0000000..c74beab --- /dev/null +++ b/WebCore/plugins/win/PluginMessageThrottlerWin.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PluginMessageThrottlerWin_h +#define PluginMessageThrottlerWin_h + +#include "Timer.h" + +#include <windows.h> + +namespace WebCore { + class PluginView; + + struct PluginMessage { + HWND hWnd; + UINT msg; + WPARAM wParam; + LPARAM lParam; + + struct PluginMessage* next; + }; + + class PluginMessageThrottlerWin { + public: + PluginMessageThrottlerWin(PluginView*); + ~PluginMessageThrottlerWin(); + + void appendMessage(HWND, UINT msg, WPARAM, LPARAM); + + private: + void messageThrottleTimerFired(Timer<PluginMessageThrottlerWin>*); + PluginMessage* allocateMessage(); + bool isInlineMessage(PluginMessage* message); + void freeMessage(PluginMessage* message); + + PluginView* m_pluginView; + PluginMessage* m_back; + PluginMessage* m_front; + + static const int NumInlineMessages = 4; + PluginMessage m_inlineMessages[NumInlineMessages]; + PluginMessage* m_freeInlineMessages; + + Timer<PluginMessageThrottlerWin> m_messageThrottleTimer; + }; + +} // namespace WebCore + +#endif // PluginMessageThrottlerWin_h diff --git a/WebCore/plugins/win/PluginPackageWin.cpp b/WebCore/plugins/win/PluginPackageWin.cpp index c744822..d2c26e2 100644 --- a/WebCore/plugins/win/PluginPackageWin.cpp +++ b/WebCore/plugins/win/PluginPackageWin.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora, Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,129 +24,57 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <shlwapi.h> #include "config.h" #include "PluginPackage.h" +#include "CString.h" +#include "MIMETypeRegistry.h" +#include "PluginDatabase.h" +#include "PluginDebug.h" #include "Timer.h" -#include "DeprecatedString.h" #include "npruntime_impl.h" -#include "PluginDebug.h" +#include <string.h> +#include <wtf/OwnArrayPtr.h> +#include <shlwapi.h> namespace WebCore { -PluginPackage::~PluginPackage() -{ - ASSERT(!m_isLoaded); -} - static String getVersionInfo(const LPVOID versionInfoData, const String& info) { LPVOID buffer; UINT bufferLength; String subInfo = "\\StringfileInfo\\040904E4\\" + info; - - bool retval = VerQueryValueW(versionInfoData, const_cast<UChar*>(subInfo.charactersWithNullTermination()), - &buffer, &bufferLength); + bool retval = VerQueryValueW(versionInfoData, + const_cast<UChar*>(subInfo.charactersWithNullTermination()), + &buffer, &bufferLength); if (!retval || bufferLength == 0) return String(); - // Subtract 1 from the length; we don't want the trailing 0 + // Subtract 1 from the length; we don't want the trailing null character. return String(reinterpret_cast<UChar*>(buffer), bufferLength - 1); } -static Vector<String> splitString(const String& str, char delimiter, int padTo) -{ - int pos = 0; - int newPos; - Vector<String> result; - DeprecatedString ds = str.deprecatedString(); - String s; - do { - - newPos = ds.find(delimiter, pos); - - if (newPos == -1) - s = ds.mid(pos); - else - s = ds.mid(pos, newPos - pos); - - if (!s.isEmpty()) - result.append(s); - - pos = newPos + 1; - } while (newPos != -1); - - while (padTo != -1 && static_cast<int>(result.size()) < padTo) - result.append(""); - - return result; -} - -void PluginPackage::freeLibrarySoon() -{ - ASSERT(!m_freeLibraryTimer.isActive()); - ASSERT(m_module); - ASSERT(m_loadCount == 0); - - m_freeLibraryTimer.startOneShot(0); -} - -void PluginPackage::freeLibraryTimerFired(Timer<PluginPackage>* /*timer*/) -{ - ASSERT(m_module); - ASSERT(m_loadCount == 0); - - ::FreeLibrary(m_module); - m_module = 0; -} - -PluginPackage::PluginPackage(const String& path, const FILETIME& lastModified) - : m_path(path) - , m_module(0) - , m_lastModified(lastModified) - , m_isLoaded(false) - , m_loadCount(0) - , m_freeLibraryTimer(this, &PluginPackage::freeLibraryTimerFired) - , m_fileVersionLS(0) - , m_fileVersionMS(0) -{ - m_fileName = String(PathFindFileName(m_path.charactersWithNullTermination())); - m_parentDirectory = m_path.left(m_path.length() - m_fileName.length() - 1); -} - -int PluginPackage::compareFileVersion(unsigned compareVersionMS, unsigned compareVersionLS) const +int PluginPackage::compareFileVersion(const PlatformModuleVersion& compareVersion) const { // return -1, 0, or 1 if plug-in version is less than, equal to, or greater than // the passed version - if (m_fileVersionMS != compareVersionMS) - return m_fileVersionMS > compareVersionMS ? 1 : -1; - if (m_fileVersionLS != compareVersionLS) - return m_fileVersionLS > compareVersionLS ? 1 : -1; + if (m_moduleVersion.mostSig != compareVersion.mostSig) + return m_moduleVersion.mostSig > compareVersion.mostSig ? 1 : -1; + if (m_moduleVersion.leastSig != compareVersion.leastSig) + return m_moduleVersion.leastSig > compareVersion.leastSig ? 1 : -1; return 0; } -void PluginPackage::storeFileVersion(LPVOID versionInfoData) -{ - VS_FIXEDFILEINFO* info; - UINT infoSize; - if (!VerQueryValue(versionInfoData, TEXT("\\"), (LPVOID*) &info, &infoSize) || infoSize < sizeof(VS_FIXEDFILEINFO)) - return; - m_fileVersionLS = info->dwFileVersionLS; - m_fileVersionMS = info->dwFileVersionMS; -} - bool PluginPackage::isPluginBlacklisted() { - static const unsigned silverlightPluginMinRequiredVersionMS = 0x00010000; - static const unsigned silverlightPluginMinRequiredVersionLS = 0x51BE0000; - if (name() == "Silverlight Plug-In") { // workaround for <rdar://5557379> Crash in Silverlight when opening microsoft.com. // the latest 1.0 version of Silverlight does not reproduce this crash, so allow it // and any newer versions - if (compareFileVersion(silverlightPluginMinRequiredVersionMS, silverlightPluginMinRequiredVersionLS) < 0) + 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 @@ -154,58 +83,138 @@ bool PluginPackage::isPluginBlacklisted() return false; } +void PluginPackage::determineQuirks(const String& mimeType) +{ + if (mimeType == "application/x-shockwave-flash") { + static const PlatformModuleVersion flashTenVersion(0x00000000, 0x000a0000); + + // Pre 10 Flash only requests windowless plugins if we return a mozilla user agent + if (compareFileVersion(flashTenVersion) < 0) + m_quirks.add(PluginQuirkWantsMozillaUserAgent); + + m_quirks.add(PluginQuirkThrottleInvalidate); + m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages); + m_quirks.add(PluginQuirkFlashURLNotifyBug); + } + + if (name().contains("Microsoft") && name().contains("Windows Media")) { + // The WMP plugin sets its size on the first NPP_SetWindow call and never updates its size, so + // call SetWindow when the plugin view has a correct size + m_quirks.add(PluginQuirkDeferFirstSetWindowCall); + + // Windowless mode does not work at all with the WMP plugin so just remove that parameter + // and don't pass it to the plug-in. + m_quirks.add(PluginQuirkRemoveWindowlessVideoParam); + + // WMP has a modal message loop that it enters whenever we call it or + // ask it to paint. This modal loop can deliver messages to other + // windows in WebKit at times when they are not expecting them (for + // example, delivering a WM_PAINT message during a layout), and these + // can cause crashes. + m_quirks.add(PluginQuirkHasModalMessageLoop); + } + + if (name() == "VLC Multimedia Plugin") { + // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window handle + m_quirks.add(PluginQuirkDontSetNullWindowHandleOnDestroy); + + // VLC 0.8.6d and 0.8.6e crash if multiple instances are created. + // <rdar://problem/5773070> tracks allowing multiple instances when this + // bug is fixed. + m_quirks.add(PluginQuirkDontAllowMultipleInstances); + } + + // The DivX plugin sets its size on the first NPP_SetWindow call and never updates its size, so + // call SetWindow when the plugin view has a correct size + if (mimeType == "video/divx") + m_quirks.add(PluginQuirkDeferFirstSetWindowCall); + + // FIXME: This is a workaround for a problem in our NPRuntime bindings; if a plug-in creates an + // NPObject and passes it to a function it's not possible to see what root object that NPObject belongs to. + // Thus, we don't know that the object should be invalidated when the plug-in instance goes away. + // See <rdar://problem/5487742>. + if (mimeType == "application/x-silverlight") + m_quirks.add(PluginQuirkDontUnloadPlugin); + + if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) { + // Because a single process cannot create multiple VMs, and we cannot reliably unload a + // Java VM, we cannot unload the Java plugin, or we'll lose reference to our only VM + m_quirks.add(PluginQuirkDontUnloadPlugin); + + // Setting the window region to an empty region causes bad scrolling repaint problems + // with the Java plug-in. + m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling); + } + + if (mimeType == "audio/x-pn-realaudio-plugin") { + // Prevent the Real plugin from calling the Window Proc recursively, causing the stack to overflow. + m_quirks.add(PluginQuirkDontCallWndProcForSameMessageRecursively); + + static const PlatformModuleVersion lastKnownUnloadableRealPlayerVersion(0x000B0B24, 0x00060000); + + // Unloading RealPlayer versions newer than 10.5 can cause a hang; see rdar://5669317. + // FIXME: Resume unloading when this bug in the RealPlayer Plug-In is fixed (rdar://5713147) + if (compareFileVersion(lastKnownUnloadableRealPlayerVersion) > 0) + m_quirks.add(PluginQuirkDontUnloadPlugin); + } +} + bool PluginPackage::fetchInfo() { DWORD versionInfoSize, zeroHandle; versionInfoSize = GetFileVersionInfoSizeW(m_path.charactersWithNullTermination(), &zeroHandle); - if (versionInfoSize == 0) return false; - LPVOID versionInfoData = fastMalloc(versionInfoSize); + OwnArrayPtr<char> versionInfoData(new char[versionInfoSize]); - if (!GetFileVersionInfoW(m_path.charactersWithNullTermination(), 0, versionInfoSize, versionInfoData)) { - fastFree(versionInfoData); + if (!GetFileVersionInfoW(m_path.charactersWithNullTermination(), 0, versionInfoSize, versionInfoData.get())) return false; - } - - m_name = getVersionInfo(versionInfoData, "ProductName"); - m_description = getVersionInfo(versionInfoData, "FileDescription"); - if (m_name.isNull() || m_description.isNull()) { - fastFree(versionInfoData); + m_name = getVersionInfo(versionInfoData.get(), "ProductName"); + m_description = getVersionInfo(versionInfoData.get(), "FileDescription"); + if (m_name.isNull() || m_description.isNull()) return false; - } - storeFileVersion(versionInfoData); + VS_FIXEDFILEINFO* info; + UINT infoSize; + if (!VerQueryValue(versionInfoData.get(), TEXT("\\"), (LPVOID*) &info, &infoSize) || infoSize < sizeof(VS_FIXEDFILEINFO)) + return false; + m_moduleVersion.leastSig = info->dwFileVersionLS; + m_moduleVersion.mostSig = info->dwFileVersionMS; - if (isPluginBlacklisted()) { - fastFree(versionInfoData); + if (isPluginBlacklisted()) return false; - } - Vector<String> mimeTypes = splitString(getVersionInfo(versionInfoData, "MIMEType"), '|', -1); - Vector<String> fileExtents = splitString(getVersionInfo(versionInfoData, "FileExtents"), '|', mimeTypes.size()); - Vector<String> descriptions = splitString(getVersionInfo(versionInfoData, "FileOpenName"), '|', mimeTypes.size()); + Vector<String> 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] : ""; - fastFree(versionInfoData); + Vector<String> extensionsVector; + extensionList.split(',', extensionsVector); - for (unsigned i = 0; i < mimeTypes.size(); i++) { - // Get rid of the extension list in the description string - String description = descriptions[i]; + // 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 + // There might be a space that we need to get rid of. if (pos > 1 && description[pos - 1] == ' ') pos--; - description = description.left(pos); } - mimeTypes[i] = mimeTypes[i].lower(); + // Determine the quirks for the MIME types this plug-in supports + determineQuirks(type); - m_mimeToExtensions.add(mimeTypes[i], splitString(fileExtents[i], ',', -1)); - m_mimeToDescriptions.add(mimeTypes[i], description); + m_mimeToExtensions.add(type, extensionsVector); + m_mimeToDescriptions.add(type, description); } return true; @@ -217,6 +226,8 @@ bool PluginPackage::load() ASSERT(m_module); m_freeLibraryTimer.stop(); } else if (m_isLoaded) { + if (m_quirks.contains(PluginQuirkDontAllowMultipleInstances)) + return false; m_loadCount++; return true; } else { @@ -267,6 +278,7 @@ bool PluginPackage::load() memset(&m_browserFuncs, 0, sizeof(m_browserFuncs)); m_browserFuncs.size = sizeof (m_browserFuncs); m_browserFuncs.version = NP_VERSION_MINOR; + m_browserFuncs.geturl = NPN_GetURL; m_browserFuncs.posturl = NPN_PostURL; m_browserFuncs.requestread = NPN_RequestRead; @@ -290,6 +302,7 @@ bool PluginPackage::load() 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; @@ -311,6 +324,7 @@ bool PluginPackage::load() m_browserFuncs.hasmethod = _NPN_HasMethod; m_browserFuncs.setexception = _NPN_SetException; m_browserFuncs.enumerate = _NPN_Enumerate; + m_browserFuncs.construct = _NPN_Construct; npErr = NP_Initialize(&m_browserFuncs); LOG_NPERROR(npErr); @@ -320,69 +334,41 @@ bool PluginPackage::load() m_loadCount++; return true; + abort: unloadWithoutShutdown(); return false; } -void PluginPackage::unload() -{ - if (!m_isLoaded) - return; - - if (--m_loadCount > 0) - return; - - m_NPP_Shutdown(); - - unloadWithoutShutdown(); -} - -void PluginPackage::unloadWithoutShutdown() -{ - if (!m_isLoaded) - return; - - ASSERT(m_loadCount == 0); - ASSERT(m_module); - - // <rdar://5530519>: Crash when closing tab with pdf file (Reader 7 only) - // If the plugin has subclassed its parent window, as with Reader 7, we may have - // gotten here by way of the plugin's internal window proc forwarding a message to our - // original window proc. If we free the plugin library from here, we will jump back - // to code we just freed when we return, so delay calling FreeLibrary at least until - // the next message loop - freeLibrarySoon(); - - m_isLoaded = false; -} - -PluginPackage* PluginPackage::createPackage(const String& path, const FILETIME& lastModified) -{ - PluginPackage* package = new PluginPackage(path, lastModified); - - if (!package->fetchInfo()) { - delete package; - return 0; - } - - return package; -} - unsigned PluginPackage::hash() const { - unsigned hashCodes[3] = { + const unsigned hashCodes[] = { + m_name.impl()->hash(), m_description.impl()->hash(), - m_lastModified.dwLowDateTime, - m_lastModified.dwHighDateTime + m_mimeToExtensions.size() }; - return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 3 * sizeof(unsigned) / sizeof(UChar)); + return StringImpl::computeHash(reinterpret_cast<const UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); } bool PluginPackage::equal(const PluginPackage& a, const PluginPackage& b) { - return a.m_description == b.m_description && (CompareFileTime(&a.m_lastModified, &b.m_lastModified) == 0); + if (a.m_name != b.m_name) + return false; + + if (a.m_description != b.m_description) + return false; + + if (a.m_mimeToExtensions.size() != b.m_mimeToExtensions.size()) + return false; + + MIMEToExtensionsMap::const_iterator::Keys end = a.m_mimeToExtensions.end().keys(); + for (MIMEToExtensionsMap::const_iterator::Keys it = a.m_mimeToExtensions.begin().keys(); it != end; ++it) { + if (!b.m_mimeToExtensions.contains(*it)) + return false; + } + + return true; } } diff --git a/WebCore/plugins/win/PluginViewWin.cpp b/WebCore/plugins/win/PluginViewWin.cpp index b219fa5..127d3fc 100644 --- a/WebCore/plugins/win/PluginViewWin.cpp +++ b/WebCore/plugins/win/PluginViewWin.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. 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 @@ -25,6 +25,7 @@ */ #include "config.h" + #include "PluginView.h" #include "Document.h" @@ -40,6 +41,7 @@ #include "Image.h" #include "HTMLNames.h" #include "HTMLPlugInElement.h" +#include "JSDOMWindow.h" #include "KeyboardEvent.h" #include "MIMETypeRegistry.h" #include "MouseEvent.h" @@ -47,25 +49,42 @@ #include "Page.h" #include "FocusController.h" #include "PlatformMouseEvent.h" +#include "PluginMessageThrottlerWin.h" #include "PluginPackage.h" -#include "kjs_binding.h" -#include "kjs_proxy.h" -#include "kjs_window.h" +#include "PluginMainThreadScheduler.h" +#include "JSDOMBinding.h" +#include "ScriptController.h" +#include "PluginDatabase.h" #include "PluginDebug.h" #include "PluginPackage.h" +#include "c_instance.h" #include "npruntime_impl.h" #include "runtime_root.h" #include "Settings.h" -#include <kjs/JSLock.h> -#include <kjs/value.h> +#include "runtime.h" +#include <runtime/JSLock.h> +#include <runtime/JSValue.h> #include <wtf/ASCIICType.h> -using KJS::ExecState; -using KJS::JSLock; -using KJS::JSObject; -using KJS::JSValue; -using KJS::UString; -using KJS::Window; +#if PLATFORM(QT) +#include <QWidget.h> +#endif + +static inline HWND windowHandleForPlatformWidget(PlatformWidget widget) +{ +#if PLATFORM(QT) + if (!widget) + return 0; + return widget->winId(); +#else + return widget; +#endif +} + +using JSC::ExecState; +using JSC::JSLock; +using JSC::JSObject; +using JSC::UString; using std::min; @@ -73,156 +92,13 @@ using namespace WTF; namespace WebCore { -using namespace EventNames; using namespace HTMLNames; -class PluginRequest { -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; -}; - -static const double MessageThrottleTimeInterval = 0.001; -static int s_callingPlugin; - -class PluginMessageThrottlerWin { -public: - PluginMessageThrottlerWin(PluginView* pluginView) - : m_back(0), m_front(0) - , m_pluginView(pluginView) - , m_messageThrottleTimer(this, &PluginMessageThrottlerWin::messageThrottleTimerFired) - { - // Initialize the free list with our inline messages - for (unsigned i = 0; i < NumInlineMessages - 1; i++) - m_inlineMessages[i].next = &m_inlineMessages[i + 1]; - m_inlineMessages[NumInlineMessages - 1].next = 0; - m_freeInlineMessages = &m_inlineMessages[0]; - } - - ~PluginMessageThrottlerWin() - { - PluginMessage* next; - - for (PluginMessage* message = m_front; message; message = next) { - next = message->next; - freeMessage(message); - } - } - - void appendMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) - { - PluginMessage* message = allocateMessage(); - - message->hWnd = hWnd; - message->msg = msg; - message->wParam = wParam; - message->lParam = lParam; - message->next = 0; - - if (m_back) - m_back->next = message; - m_back = message; - if (!m_front) - m_front = message; - - if (!m_messageThrottleTimer.isActive()) - m_messageThrottleTimer.startOneShot(MessageThrottleTimeInterval); - } - -private: - struct PluginMessage { - HWND hWnd; - UINT msg; - WPARAM wParam; - LPARAM lParam; - - struct PluginMessage* next; - }; - - void messageThrottleTimerFired(Timer<PluginMessageThrottlerWin>*) - { - PluginMessage* message = m_front; - m_front = m_front->next; - if (message == m_back) - m_back = 0; - - ::CallWindowProc(m_pluginView->pluginWndProc(), message->hWnd, message->msg, message->wParam, message->lParam); - - freeMessage(message); - - if (m_front) - m_messageThrottleTimer.startOneShot(MessageThrottleTimeInterval); - } - - PluginMessage* allocateMessage() - { - PluginMessage *message; - - if (m_freeInlineMessages) { - message = m_freeInlineMessages; - m_freeInlineMessages = message->next; - } else - message = new PluginMessage; - - return message; - } - - bool isInlineMessage(PluginMessage* message) - { - return message >= &m_inlineMessages[0] && message <= &m_inlineMessages[NumInlineMessages - 1]; - } - - void freeMessage(PluginMessage* message) - { - if (isInlineMessage(message)) { - message->next = m_freeInlineMessages; - m_freeInlineMessages = message; - } else - delete 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; -}; - -static String scriptStringIfJavaScriptURL(const KURL& url) -{ - if (!url.string().startsWith("javascript:", false)) - return String(); - - // This returns an unescaped string - return KURL::decode_string(url.deprecatedString().mid(11)); -} - -PluginView* PluginView::s_currentPluginView = 0; - const LPCWSTR kWebPluginViewdowClassName = L"WebPluginView"; const LPCWSTR kWebPluginViewProperty = L"WebPluginViewProperty"; static const char* MozillaUserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0"; -static LRESULT CALLBACK PluginViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); - static bool registerPluginView() { static bool haveRegisteredWindowClass = false; @@ -231,6 +107,10 @@ static bool registerPluginView() haveRegisteredWindowClass = true; +#if PLATFORM(QT) + Page::setInstanceHandle((HINSTANCE)(qWinAppInst())); +#endif + ASSERT(Page::instanceHandle()); WNDCLASSEX wcex; @@ -252,19 +132,13 @@ static bool registerPluginView() return !!RegisterClassEx(&wcex); } -static LRESULT CALLBACK PluginViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +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); } -void PluginView::popPopupsStateTimerFired(Timer<PluginView>*) -{ - popPopupsEnabledState(); -} - - static bool isWindowsMessageUserGesture(UINT message) { switch (message) { @@ -299,12 +173,12 @@ PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } if (message == m_lastMessage && - m_quirks.contains(PluginQuirkDontCallWndProcForSameMessageRecursively) && + m_plugin->quirks().contains(PluginQuirkDontCallWndProcForSameMessageRecursively) && m_isCallingPluginWndProc) return 1; if (message == WM_USER + 1 && - m_quirks.contains(PluginQuirkThrottleWMUserPlusOneMessages)) { + m_plugin->quirks().contains(PluginQuirkThrottleWMUserPlusOneMessages)) { if (!m_messageThrottler) m_messageThrottler.set(new PluginMessageThrottlerWin(this)); @@ -321,7 +195,7 @@ PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) // 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); @@ -335,7 +209,7 @@ PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return result; } -void PluginView::updateWindow() const +void PluginView::updatePluginWidget() const { if (!parent()) return; @@ -346,11 +220,11 @@ void PluginView::updateWindow() const IntRect oldWindowRect = m_windowRect; IntRect oldClipRect = m_clipRect; - m_windowRect = IntRect(frameView->contentsToWindow(frameGeometry().location()), frameGeometry().size()); + m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); m_clipRect = windowClipRect(); m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); - if (m_window && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) { + if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) { HRGN rgn; setCallingPlugin(true); @@ -358,96 +232,66 @@ void PluginView::updateWindow() const // To prevent flashes while scrolling, we disable drawing during the window // update process by clipping the window to the zero rect. - bool clipToZeroRect = !m_quirks.contains(PluginQuirkDontClipToZeroRectWhenScrolling); + bool clipToZeroRect = !m_plugin->quirks().contains(PluginQuirkDontClipToZeroRectWhenScrolling); if (clipToZeroRect) { rgn = ::CreateRectRgn(0, 0, 0, 0); - ::SetWindowRgn(m_window, rgn, FALSE); + ::SetWindowRgn(platformPluginWidget(), rgn, FALSE); } else { rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom()); - ::SetWindowRgn(m_window, rgn, TRUE); + ::SetWindowRgn(platformPluginWidget(), rgn, TRUE); } if (m_windowRect != oldWindowRect) - ::MoveWindow(m_window, m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), TRUE); + ::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(m_window, rgn, TRUE); + ::SetWindowRgn(platformPluginWidget(), rgn, TRUE); } setCallingPlugin(false); } } -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::setFrameGeometry(const IntRect& rect) -{ - if (m_element->document()->printing()) - return; - - if (rect != frameGeometry()) - Widget::setFrameGeometry(rect); - - updateWindow(); - setNPWindowRect(rect); -} - -void PluginView::geometryChanged() const -{ - updateWindow(); -} - void PluginView::setFocus() { - if (m_window) - SetFocus(m_window); + if (platformPluginWidget()) + SetFocus(platformPluginWidget()); Widget::setFocus(); } void PluginView::show() { - m_isVisible = true; + setSelfVisible(true); - if (m_attachedToWindow && m_window) - ShowWindow(m_window, SW_SHOWNA); + if (isParentVisible() && platformPluginWidget()) + ShowWindow(platformPluginWidget(), SW_SHOWNA); Widget::show(); } void PluginView::hide() { - m_isVisible = false; + setSelfVisible(false); - if (m_attachedToWindow && m_window) - ShowWindow(m_window, SW_HIDE); + if (isParentVisible() && platformPluginWidget()) + ShowWindow(platformPluginWidget(), SW_HIDE); Widget::hide(); } void PluginView::paintMissingPluginIcon(GraphicsContext* context, const IntRect& rect) { - static Image* nullPluginImage; + static RefPtr<Image> nullPluginImage; if (!nullPluginImage) nullPluginImage = Image::loadPlatformResource("nullPlugin"); - IntRect imageRect(frameGeometry().x(), frameGeometry().y(), nullPluginImage->width(), nullPluginImage->height()); + IntRect imageRect(frameRect().x(), frameRect().y(), nullPluginImage->width(), nullPluginImage->height()); - int xOffset = (frameGeometry().width() - imageRect.width()) / 2; - int yOffset = (frameGeometry().height() - imageRect.height()) / 2; + int xOffset = (frameRect().width() - imageRect.width()) / 2; + int yOffset = (frameRect().height() - imageRect.height()) / 2; imageRect.move(xOffset, yOffset); @@ -456,7 +300,7 @@ void PluginView::paintMissingPluginIcon(GraphicsContext* context, const IntRect& context->save(); context->clip(windowClipRect()); - context->drawImage(nullPluginImage, imageRect.location()); + context->drawImage(nullPluginImage.get(), imageRect.location()); context->restore(); } @@ -472,7 +316,7 @@ bool PluginView::dispatchNPEvent(NPEvent& npEvent) shouldPop = true; } - KJS::JSLock::DropAllLocks dropAllLocks; + JSC::JSLock::DropAllLocks dropAllLocks(false); setCallingPlugin(true); bool result = m_plugin->pluginFuncs()->event(m_instance, &npEvent); setCallingPlugin(false); @@ -495,31 +339,36 @@ void PluginView::paint(GraphicsContext* context, const IntRect& rect) return; ASSERT(parent()->isFrameView()); - IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameGeometry()); + IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect()); HDC hdc = context->getWindowsContext(rectInWindow, m_isTransparent); NPEvent npEvent; + // On Safari/Windows without transparency layers the GraphicsContext returns the HDC + // of the window and the plugin expects that the passed in DC has window coordinates. + // In the Qt port we always draw in an offscreen buffer and therefore need to preserve + // the translation set in getWindowsContext. +#if !PLATFORM(QT) if (!context->inTransparencyLayer()) { - // The plugin expects that the passed in DC has window coordinates. XFORM transform; GetWorldTransform(hdc, &transform); transform.eDx = 0; transform.eDy = 0; SetWorldTransform(hdc, &transform); } +#endif m_npWindow.type = NPWindowTypeDrawable; m_npWindow.window = hdc; - IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(frameGeometry().location()); + IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location()); WINDOWPOS windowpos; memset(&windowpos, 0, sizeof(windowpos)); windowpos.x = p.x(); windowpos.y = p.y(); - windowpos.cx = frameGeometry().width(); - windowpos.cy = frameGeometry().height(); + windowpos.cx = frameRect().width(); + windowpos.cy = frameRect().height(); npEvent.event = WM_WINDOWPOSCHANGED; npEvent.lParam = reinterpret_cast<uint32>(&windowpos); @@ -527,7 +376,7 @@ void PluginView::paint(GraphicsContext* context, const IntRect& rect) dispatchNPEvent(npEvent); - setNPWindowRect(frameGeometry()); + setNPWindowRect(frameRect()); npEvent.event = WM_PAINT; npEvent.wParam = reinterpret_cast<uint32>(hdc); @@ -538,7 +387,7 @@ void PluginView::paint(GraphicsContext* context, const IntRect& rect) dispatchNPEvent(npEvent); - context->releaseWindowsContext(hdc, frameGeometry(), m_isTransparent); + context->releaseWindowsContext(hdc, frameRect(), m_isTransparent); } void PluginView::handleKeyboardEvent(KeyboardEvent* event) @@ -547,15 +396,15 @@ void PluginView::handleKeyboardEvent(KeyboardEvent* event) npEvent.wParam = event->keyCode(); - if (event->type() == keydownEvent) { + if (event->type() == eventNames().keydownEvent) { npEvent.event = WM_KEYDOWN; npEvent.lParam = 0; - } else if (event->type() == keyupEvent) { + } else if (event->type() == eventNames().keyupEvent) { npEvent.event = WM_KEYUP; npEvent.lParam = 0x8000; } - KJS::JSLock::DropAllLocks; + JSC::JSLock::DropAllLocks dropAllLocks(false); if (!dispatchNPEvent(npEvent)) event->setDefaultHandled(); } @@ -577,9 +426,9 @@ void PluginView::handleMouseEvent(MouseEvent* event) if (event->shiftKey()) npEvent.wParam |= MK_SHIFT; - if (event->type() == mousemoveEvent || - event->type() == mouseoutEvent || - event->type() == mouseoverEvent) { + if (event->type() == eventNames().mousemoveEvent || + event->type() == eventNames().mouseoutEvent || + event->type() == eventNames().mouseoverEvent) { npEvent.event = WM_MOUSEMOVE; if (event->buttonDown()) switch (event->button()) { @@ -594,7 +443,7 @@ void PluginView::handleMouseEvent(MouseEvent* event) break; } } - else if (event->type() == mousedownEvent) { + else if (event->type() == eventNames().mousedownEvent) { // Focus the plugin if (Page* page = m_parentFrame->page()) page->focusController()->setFocusedFrame(m_parentFrame); @@ -610,7 +459,7 @@ void PluginView::handleMouseEvent(MouseEvent* event) npEvent.event = WM_RBUTTONDOWN; break; } - } else if (event->type() == mouseupEvent) { + } else if (event->type() == eventNames().mouseupEvent) { switch (event->button()) { case 0: npEvent.event = WM_LBUTTONUP; @@ -627,25 +476,16 @@ void PluginView::handleMouseEvent(MouseEvent* event) HCURSOR currentCursor = ::GetCursor(); - KJS::JSLock::DropAllLocks; + JSC::JSLock::DropAllLocks dropAllLocks(false); if (!dispatchNPEvent(npEvent)) event->setDefaultHandled(); +#if !PLATFORM(QT) // Currently, Widget::setCursor is always called after this function in EventHandler.cpp // and since we don't want that we set ignoreNextSetCursor to true here to prevent that. ignoreNextSetCursor = true; lastSetCursor = ::GetCursor(); -} - -void PluginView::handleEvent(Event* event) -{ - if (!m_plugin || m_isWindowed) - return; - - if (event->isMouseEvent()) - handleMouseEvent(static_cast<MouseEvent*>(event)); - else if (event->isKeyboardEvent()) - handleKeyboardEvent(static_cast<KeyboardEvent*>(event)); +#endif } void PluginView::setParent(ScrollView* parent) @@ -655,37 +495,32 @@ void PluginView::setParent(ScrollView* parent) if (parent) init(); else { - if (!m_window) + 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 (m_window == focusedWindow || ::IsChild(m_window, focusedWindow)) + if (platformPluginWidget() == focusedWindow || ::IsChild(platformPluginWidget(), focusedWindow)) ::SetFocus(0); } } -void PluginView::attachToWindow() +void PluginView::setParentVisible(bool visible) { - if (m_attachedToWindow) + if (isParentVisible() == visible) return; - m_attachedToWindow = true; - if (m_isVisible && m_window) - ShowWindow(m_window, SW_SHOWNA); -} - -void PluginView::detachFromWindow() -{ - if (!m_attachedToWindow) - return; + Widget::setParentVisible(visible); - if (m_isVisible && m_window) - ShowWindow(m_window, SW_HIDE); - m_attachedToWindow = false; + if (isSelfVisible() && platformPluginWidget()) { + if (visible) + ShowWindow(platformPluginWidget(), SW_SHOWNA); + else + ShowWindow(platformPluginWidget(), SW_HIDE); + } } void PluginView::setNPWindowRect(const IntRect& rect) @@ -706,7 +541,7 @@ void PluginView::setNPWindowRect(const IntRect& rect) m_npWindow.clipRect.bottom = rect.height(); if (m_plugin->pluginFuncs()->setwindow) { - KJS::JSLock::DropAllLocks dropAllLocks; + JSC::JSLock::DropAllLocks dropAllLocks(false); setCallingPlugin(true); m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); setCallingPlugin(false); @@ -714,46 +549,12 @@ void PluginView::setNPWindowRect(const IntRect& rect) if (!m_isWindowed) return; - ASSERT(m_window); + ASSERT(platformPluginWidget()); - WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(m_window, GWLP_WNDPROC); + WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC); if (currentWndProc != PluginViewWndProc) - m_pluginWndProc = (WNDPROC)SetWindowLongPtr(m_window, GWLP_WNDPROC, (LONG)PluginViewWndProc); - } -} - -bool PluginView::start() -{ - if (m_isStarted) - return false; - - ASSERT(m_plugin); - ASSERT(m_plugin->pluginFuncs()->newp); - - NPError npErr; - PluginView::setCurrentPluginView(this); - { - KJS::JSLock::DropAllLocks dropAllLocks; - setCallingPlugin(true); - npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.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) - return false; - - m_isStarted = true; - - if (!m_url.isEmpty() && !m_loadManually) { - FrameLoadRequest frameLoadRequest; - frameLoadRequest.resourceRequest().setHTTPMethod("GET"); - frameLoadRequest.resourceRequest().setURL(m_url); - load(frameLoadRequest, false, 0); + m_pluginWndProc = (WNDPROC)SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG)PluginViewWndProc); } - - return true; } void PluginView::stop() @@ -774,22 +575,24 @@ void PluginView::stop() // Unsubclass the window if (m_isWindowed) { - WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(m_window, GWLP_WNDPROC); + WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC); if (currentWndProc == PluginViewWndProc) - SetWindowLongPtr(m_window, GWLP_WNDPROC, (LONG)m_pluginWndProc); + SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG)m_pluginWndProc); } - KJS::JSLock::DropAllLocks; + JSC::JSLock::DropAllLocks dropAllLocks(false); // Clear the window m_npWindow.window = 0; - if (m_plugin->pluginFuncs()->setwindow && !m_quirks.contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) { + if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) { setCallingPlugin(true); m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); setCallingPlugin(false); } + PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance); + // Destroy the plugin NPSavedData* savedData = 0; setCallingPlugin(true); @@ -806,489 +609,68 @@ void PluginView::stop() m_instance->pdata = 0; } -void PluginView::setCurrentPluginView(PluginView* pluginView) +const char* PluginView::userAgentStatic() { - 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; -} - -static void freeStringArray(char** stringArray, int length) -{ - if (!stringArray) - return; - - for (int i = 0; i < length; i++) - fastFree(stringArray[i]); - - fastFree(stringArray); -} - -static bool getString(KJSProxy* proxy, JSValue* result, String& string) -{ - if (!proxy || !result || result->isUndefined()) - return false; - JSLock lock; - - ExecState* exec = proxy->globalObject()->globalExec(); - UString ustring = result->toString(exec); - exec->clearException(); - - string = ustring; - return true; -} - -void PluginView::performRequest(PluginRequest* request) -{ - // 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()) { - PluginStream* stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_quirks); - m_streams.add(stream); - stream->start(); - } else { - m_parentFrame->loader()->load(request->frameLoadRequest().resourceRequest(), targetFrameName); - - // FIXME: <rdar://problem/4807469> This should be sent when the document has finished loading - if (request->sendNotification()) { - KJS::JSLock::DropAllLocks dropAllLocks; - setCallingPlugin(true); - m_plugin->pluginFuncs()->urlnotify(m_instance, requestURL.deprecatedString().utf8(), NPRES_DONE, request->notifyData()); - setCallingPlugin(false); - } - } - 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; - JSValue* result = m_parentFrame->loader()->executeScript(jsString, request->shouldAllowPopups()); - - if (targetFrameName.isNull()) { - String resultString; - - CString cstr; - if (getString(parentFrame->scriptProxy(), result, resultString)) - cstr = resultString.utf8(); - - RefPtr<PluginStream> stream = new PluginStream(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_quirks); - m_streams.add(stream); - stream->sendJavaScriptStream(requestURL, cstr); - } -} - -void PluginView::requestTimerFired(Timer<PluginView>* timer) -{ - ASSERT(timer == &m_requestTimer); - ASSERT(m_requests.size() > 0); - - 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); - 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; - - const String& targetFrameName = frameLoadRequest.frameName(); - String jsString = scriptStringIfJavaScriptURL(url); - - if (!jsString.isNull()) { - Settings* settings = m_parentFrame->settings(); - if (!settings || !settings->isJavaScriptEnabled()) { - // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does. - return NPERR_GENERIC_ERROR; - } - - if (!targetFrameName.isNull() && m_parentFrame->tree()->find(targetFrameName) != m_parentFrame) { - // For security reasons, only allow JS requests to be made on the frame that contains the plug-in. - return NPERR_INVALID_PARAM; - } - } - - PluginRequest* request = new PluginRequest(frameLoadRequest, sendNotification, notifyData, arePopupsAllowed()); - scheduleRequest(request); - - return NPERR_NO_ERROR; -} - -static KURL makeURL(const KURL& baseURL, const char* relativeURLString) -{ - DeprecatedString urlString = DeprecatedString::fromLatin1(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; - - frameLoadRequest.setFrameName(target); - frameLoadRequest.resourceRequest().setHTTPMethod("GET"); - frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url)); - - return load(frameLoadRequest, true, notifyData); -} - -NPError PluginView::getURL(const char* url, const char* target) -{ - FrameLoadRequest frameLoadRequest; - - frameLoadRequest.setFrameName(target); - frameLoadRequest.resourceRequest().setHTTPMethod("GET"); - frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url)); - - return load(frameLoadRequest, false, 0); -} - -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* PluginView::userAgent() { - 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 = DeprecatedString::fromLatin1(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(DeprecatedString::fromLatin1(line, colon - line)); - String value; - - for (colon++; colon != eol; colon++) { - if (*colon != ' ' && *colon != '\t') - break; - } - if (colon == eol) - value = ""; - else - value = DeprecatedString::fromLatin1(colon, eol - colon); - - String oldValue = headerFields.get(lastKey); - if (!oldValue.isNull()) { - String tmp = oldValue; - tmp += ", "; - tmp += value; - value = tmp; - } - - headerFields.set(lastKey, value); - } - } - } + if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent)) + return MozillaUserAgent; - return headerFields; + if (m_userAgent.isNull()) + m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8(); + return m_userAgent.data(); } -NPError PluginView::handlePost(const char* url, const char* target, uint32 len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders) +NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf) { - if (!url || !len || !buf) - return NPERR_INVALID_PARAM; - - FrameLoadRequest frameLoadRequest; - - HTTPHeaderMap headerFields; - Vector<char> buffer; - - if (file) { - String filename = DeprecatedString::fromLatin1(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; + String filename(buf, len); - 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); + if (filename.startsWith("file:///")) + filename = filename.substring(8); - CloseHandle(fileHandle); + // Get file info + WIN32_FILE_ATTRIBUTE_DATA attrs; + if (GetFileAttributesExW(filename.charactersWithNullTermination(), GetFileExInfoStandard, &attrs) == 0) + return NPERR_FILE_NOT_FOUND; - if (retval == 0 || bytesRead != attrs.nFileSizeLow) - return NPERR_FILE_NOT_FOUND; - } else { - buffer.resize(len); - memcpy(buffer.data(), buf, len); - } + if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return NPERR_FILE_NOT_FOUND; - const char* postData = buffer.data(); - int postDataLength = buffer.size(); + HANDLE fileHandle = CreateFileW(filename.charactersWithNullTermination(), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - 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(PassRefPtr<FormData>(new FormData(postData, postDataLength))); - frameLoadRequest.setFrameName(target); - - return load(frameLoadRequest, sendNotification, notifyData); -} - -NPError PluginView::postURLNotify(const char* url, const char* target, uint32 len, const char* buf, NPBool file, void* notifyData) -{ - return handlePost(url, target, len, buf, file, notifyData, true, true); -} + if (fileHandle == INVALID_HANDLE_VALUE) + return NPERR_FILE_NOT_FOUND; -NPError PluginView::postURL(const char* url, const char* target, uint32 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); -} + buffer.resize(attrs.nFileSizeLow); -NPError PluginView::newStream(NPMIMEType type, const char* target, NPStream** stream) -{ - notImplemented(); - // Unsupported - return NPERR_GENERIC_ERROR; -} - -int32 PluginView::write(NPStream* stream, int32 len, void* buffer) -{ - notImplemented(); - // Unsupported - return -1; -} + DWORD bytesRead; + int retval = ReadFile(fileHandle, buffer.data(), attrs.nFileSizeLow, &bytesRead, 0); -NPError PluginView::destroyStream(NPStream* stream, NPReason reason) -{ - PluginStream* browserStream = static_cast<PluginStream*>(stream->ndata); + CloseHandle(fileHandle); - if (!stream || PluginStream::ownerForStream(stream) != m_instance) - return NPERR_INVALID_INSTANCE_ERROR; + if (retval == 0 || bytesRead != attrs.nFileSizeLow) + return NPERR_FILE_NOT_FOUND; - browserStream->cancelAndDestroyStream(reason); return NPERR_NO_ERROR; } -const char* PluginView::userAgent() -{ - if (m_quirks.contains(PluginQuirkWantsMozillaUserAgent)) - return MozillaUserAgent; - - if (m_userAgent.isNull()) - m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8(); - return m_userAgent.data(); -} - -void PluginView::status(const char* message) +NPError PluginView::getValueStatic(NPNVariable variable, void* value) { - String s = DeprecatedString::fromLatin1(message); - - if (Page* page = m_parentFrame->page()) - page->chrome()->setStatusbarText(m_parentFrame, s); + return NPERR_GENERIC_ERROR; } NPError PluginView::getValue(NPNVariable variable, void* value) { switch (variable) { +#if ENABLE(NETSCAPE_PLUGIN_API) case NPNVWindowNPObject: { - NPObject* windowScriptObject = m_parentFrame->windowScriptNPObject(); + 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) @@ -1296,11 +678,14 @@ NPError PluginView::getValue(NPNVariable variable, void* value) 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)) @@ -1315,44 +700,40 @@ NPError PluginView::getValue(NPNVariable variable, void* value) return NPERR_NO_ERROR; } +#endif case NPNVnetscapeWindow: { HWND* w = reinterpret_cast<HWND*>(value); - *w = containingWindow(); + *w = windowHandleForPlatformWidget(parent() ? parent()->hostWindow()->platformWindow() : 0); return NPERR_NO_ERROR; } - default: - return NPERR_GENERIC_ERROR; - } -} -NPError PluginView::setValue(NPPVariable variable, void* value) -{ - switch (variable) { - case NPPVpluginWindowBool: - m_isWindowed = value; - return NPERR_NO_ERROR; - case NPPVpluginTransparentBool: - m_isTransparent = value; + case NPNVSupportsWindowless: { + NPBool *result = reinterpret_cast<NPBool*>(value); + + *result = TRUE; + return NPERR_NO_ERROR; + } + default: - notImplemented(); return NPERR_GENERIC_ERROR; } } -void PluginView::invalidateTimerFired(Timer<PluginView>* timer) +void PluginView::invalidateRect(const IntRect& rect) { - ASSERT(timer == &m_invalidateTimer); + if (m_isWindowed) { + RECT invalidRect = { rect.x(), rect.y(), rect.right(), rect.bottom() }; + ::InvalidateRect(platformPluginWidget(), &invalidRect, false); + return; + } - for (unsigned i = 0; i < m_invalidRects.size(); i++) - Widget::invalidateRect(m_invalidRects[i]); - m_invalidRects.clear(); + invalidateWindowlessPluginRect(rect); } - void PluginView::invalidateRect(NPRect* rect) { if (!rect) { @@ -1363,15 +744,15 @@ void PluginView::invalidateRect(NPRect* rect) IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); if (m_isWindowed) { - RECT invalidRect(r); - InvalidateRect(m_window, &invalidRect, FALSE); + RECT invalidRect = { r.x(), r.y(), r.right(), r.bottom() }; + InvalidateRect(platformPluginWidget(), &invalidRect, FALSE); } else { - if (m_quirks.contains(PluginQuirkThrottleInvalidate)) { + if (m_plugin->quirks().contains(PluginQuirkThrottleInvalidate)) { m_invalidRects.append(r); if (!m_invalidateTimer.isActive()) m_invalidateTimer.startOneShot(0.001); } else - Widget::invalidateRect(r); + invalidateRect(r); } } @@ -1387,59 +768,16 @@ void PluginView::invalidateRegion(NPRegion region) return; } - Widget::invalidateRect(r); + 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(m_window); + ::UpdateWindow(platformPluginWidget()); else - ::UpdateWindow(containingWindow()); -} - -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; -} - -KJS::Bindings::Instance* PluginView::bindingInstance() -{ - NPObject* object = 0; - - if (!m_plugin || !m_plugin->pluginFuncs()->getvalue) - return 0; - - NPError npErr; - { - KJS::JSLock::DropAllLocks dropAllLocks; - setCallingPlugin(true); - npErr = m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginScriptableNPObject, &object); - setCallingPlugin(false); - } - - if (npErr != NPERR_NO_ERROR || !object) - return 0; - - RefPtr<KJS::Bindings::RootObject> root = m_parentFrame->createRootObject(this, m_parentFrame->scriptProxy()->globalObject()); - KJS::Bindings::Instance *instance = KJS::Bindings::Instance::createBindingForLanguageInstance(KJS::Bindings::Instance::CLanguage, object, root.release()); - - _NPN_ReleaseObject(object); - - return instance; + ::UpdateWindow(windowHandleForPlatformWidget(parent() ? parent()->hostWindow()->platformWindow() : 0)); } PluginView::~PluginView() @@ -1451,155 +789,15 @@ PluginView::~PluginView() freeStringArray(m_paramNames, m_paramCount); freeStringArray(m_paramValues, m_paramCount); - if (m_window) - DestroyWindow(m_window); + if (platformPluginWidget()) + DestroyWindow(platformPluginWidget()); - m_parentFrame->cleanupScriptObjectsForPlugin(this); + m_parentFrame->script()->cleanupScriptObjectsForPlugin(this); - if (m_plugin && !m_quirks.contains(PluginQuirkDontUnloadPlugin)) + if (m_plugin && !m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin)) m_plugin->unload(); } -void PluginView::disconnectStream(PluginStream* stream) -{ - ASSERT(m_streams.contains(stream)); - - m_streams.remove(stream); -} - -void PluginView::determineQuirks(const String& mimeType) -{ - static const unsigned lastKnownUnloadableRealPlayerVersionLS = 0x000B0B24; - static const unsigned lastKnownUnloadableRealPlayerVersionMS = 0x00060000; - - if (mimeType == "application/x-shockwave-flash") { - // The flash plugin only requests windowless plugins if we return a mozilla user agent - m_quirks.add(PluginQuirkWantsMozillaUserAgent); - m_quirks.add(PluginQuirkThrottleInvalidate); - m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages); - m_quirks.add(PluginQuirkFlashURLNotifyBug); - } - - if (m_plugin->name().contains("Microsoft") && m_plugin->name().contains("Windows Media")) { - // The WMP plugin sets its size on the first NPP_SetWindow call and never updates its size, so - // call SetWindow when the plugin view has a correct size - m_quirks.add(PluginQuirkDeferFirstSetWindowCall); - - // Windowless mode does not work at all with the WMP plugin so just remove that parameter - // and don't pass it to the plug-in. - m_quirks.add(PluginQuirkRemoveWindowlessVideoParam); - - // WMP has a modal message loop that it enters whenever we call it or - // ask it to paint. This modal loop can deliver messages to other - // windows in WebKit at times when they are not expecting them (for - // example, delivering a WM_PAINT message during a layout), and these - // can cause crashes. - m_quirks.add(PluginQuirkHasModalMessageLoop); - } - - // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window handle - if (m_plugin->name() == "VLC Multimedia Plugin") - m_quirks.add(PluginQuirkDontSetNullWindowHandleOnDestroy); - - // The DivX plugin sets its size on the first NPP_SetWindow call and never updates its size, so - // call SetWindow when the plugin view has a correct size - if (mimeType == "video/divx") - m_quirks.add(PluginQuirkDeferFirstSetWindowCall); - - // FIXME: This is a workaround for a problem in our NPRuntime bindings; if a plug-in creates an - // NPObject and passes it to a function it's not possible to see what root object that NPObject belongs to. - // Thus, we don't know that the object should be invalidated when the plug-in instance goes away. - // See <rdar://problem/5487742>. - if (mimeType == "application/x-silverlight") - m_quirks.add(PluginQuirkDontUnloadPlugin); - - if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) { - // Because a single process cannot create multiple VMs, and we cannot reliably unload a - // Java VM, we cannot unload the Java plugin, or we'll lose reference to our only VM - m_quirks.add(PluginQuirkDontUnloadPlugin); - - // Setting the window region to an empty region causes bad scrolling repaint problems - // with the Java plug-in. - m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling); - } - - if (mimeType == "audio/x-pn-realaudio-plugin") { - // Prevent the Real plugin from calling the Window Proc recursively, causing the stack to overflow. - m_quirks.add(PluginQuirkDontCallWndProcForSameMessageRecursively); - - // Unloading RealPlayer versions newer than 10.5 can cause a hang; see rdar://5669317. - // FIXME: Resume unloading when this bug in the RealPlayer Plug-In is fixed (rdar://5713147) - if (m_plugin->compareFileVersion(lastKnownUnloadableRealPlayerVersionMS, lastKnownUnloadableRealPlayerVersionLS) > 0) - m_quirks.add(PluginQuirkDontUnloadPlugin); - } -} - -void PluginView::setParameters(const Vector<String>& paramNames, const Vector<String>& paramValues) -{ - ASSERT(paramNames.size() == paramValues.size()); - - 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_quirks.contains(PluginQuirkRemoveWindowlessVideoParam) && equalIgnoringCase(paramNames[i], "windowlessvideo")) - continue; - - 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())) - , m_status(PluginStatusLoadedSuccessfully) - , m_requestTimer(this, &PluginView::requestTimerFired) - , m_invalidateTimer(this, &PluginView::invalidateTimerFired) - , m_popPopupsStateTimer(this, &PluginView::popPopupsStateTimerFired) - , m_paramNames(0) - , m_paramValues(0) - , m_window(0) - , m_pluginWndProc(0) - , m_isWindowed(true) - , m_isTransparent(false) - , m_isVisible(false) - , m_attachedToWindow(false) - , m_haveInitialized(false) - , m_lastMessage(0) - , m_isCallingPluginWndProc(false) - , m_loadManually(loadManually) - , m_manualStream(0) -{ - if (!m_plugin) { - m_status = PluginStatusCanNotFindPlugin; - return; - } - - m_instance = &m_instanceStruct; - m_instance->ndata = this; - - m_mimeType = mimeType.utf8(); - determineQuirks(mimeType); - - setParameters(paramNames, paramValues); - - m_mode = m_loadManually ? NP_FULL : NP_EMBED; - - resize(size); -} - void PluginView::init() { if (m_haveInitialized) @@ -1626,82 +824,38 @@ void PluginView::init() registerPluginView(); DWORD flags = WS_CHILD; - if (m_isVisible) + if (isSelfVisible()) flags |= WS_VISIBLE; - m_window = CreateWindowEx(0, kWebPluginViewdowClassName, 0, flags, - 0, 0, 0, 0, m_parentFrame->view()->containingWindow(), 0, Page::instanceHandle(), 0); - + HWND parentWindowHandle = windowHandleForPlatformWidget(m_parentFrame->view()->hostWindow()->platformWindow()); + HWND window = ::CreateWindowEx(0, kWebPluginViewdowClassName, 0, flags, + 0, 0, 0, 0, parentWindowHandle, 0, Page::instanceHandle(), 0); +#if PLATFORM(WIN_OS) && PLATFORM(QT) + m_window = window; +#else + setPlatformWidget(window); +#endif + // Calling SetWindowLongPtrA here makes the window proc ASCII, which is required by at least // the Shockwave Director plug-in. - ::SetWindowLongPtrA(m_window, GWL_WNDPROC, (LONG)DefWindowProcA); - - SetProp(m_window, kWebPluginViewProperty, this); +#if PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC) + ::SetWindowLongPtrA(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)DefWindowProcA); +#else + ::SetWindowLongPtrA(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProcA); +#endif + SetProp(platformPluginWidget(), kWebPluginViewProperty, this); m_npWindow.type = NPWindowTypeWindow; - m_npWindow.window = m_window; + m_npWindow.window = platformPluginWidget(); } else { m_npWindow.type = NPWindowTypeDrawable; m_npWindow.window = 0; } - if (!m_quirks.contains(PluginQuirkDeferFirstSetWindowCall)) - setNPWindowRect(frameGeometry()); + if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall)) + setNPWindowRect(frameRect()); m_status = PluginStatusLoadedSuccessfully; } -void PluginView::didReceiveResponse(const ResourceResponse& response) -{ - ASSERT(m_loadManually); - ASSERT(!m_manualStream); - - m_manualStream = new PluginStream(this, m_parentFrame, m_parentFrame->loader()->activeDocumentLoader()->request(), false, 0, plugin()->pluginFuncs(), instance(), m_quirks); - m_manualStream->setLoadManually(true); - - m_manualStream->didReceiveResponse(0, response); -} - -void PluginView::didReceiveData(const char* data, int length) -{ - ASSERT(m_loadManually); - ASSERT(m_manualStream); - - m_manualStream->didReceiveData(0, data, length); -} - -void PluginView::didFinishLoading() -{ - ASSERT(m_loadManually); - ASSERT(m_manualStream); - - m_manualStream->didFinishLoading(0); -} - -void PluginView::didFail(const ResourceError& error) -{ - ASSERT(m_loadManually); - ASSERT(m_manualStream); - - m_manualStream->didFail(0, error); -} - -void PluginView::setCallingPlugin(bool b) const -{ - if (!m_quirks.contains(PluginQuirkHasModalMessageLoop)) - return; - - if (b) - ++s_callingPlugin; - else - --s_callingPlugin; - - ASSERT(s_callingPlugin >= 0); -} - -bool PluginView::isCallingPlugin() -{ - return s_callingPlugin > 0; -} - } // namespace WebCore diff --git a/WebCore/plugins/wx/PluginDataWx.cpp b/WebCore/plugins/wx/PluginDataWx.cpp new file mode 100644 index 0000000..28e3967 --- /dev/null +++ b/WebCore/plugins/wx/PluginDataWx.cpp @@ -0,0 +1,44 @@ +/* + * 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" + +namespace WebCore { + +void PluginData::initPlugins() +{ + notImplemented(); +} + +void PluginData::refresh() +{ + notImplemented(); +} + +}; diff --git a/WebCore/plugins/wx/PluginPackageWx.cpp b/WebCore/plugins/wx/PluginPackageWx.cpp new file mode 100644 index 0000000..b93ead2 --- /dev/null +++ b/WebCore/plugins/wx/PluginPackageWx.cpp @@ -0,0 +1,74 @@ +/* + * 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" + +#include "CString.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "npruntime_impl.h" +#include "PluginDatabase.h" +#include "PluginDebug.h" + +namespace WebCore { + +void PluginPackage::determineQuirks(const String& mimeType) +{ + notImplemented(); +} + +bool PluginPackage::fetchInfo() +{ + notImplemented(); + return false; +} + +bool PluginPackage::load() +{ + notImplemented(); + return false; +} + +unsigned PluginPackage::hash() const +{ + notImplemented(); + + return 0; +} + +bool PluginPackage::equal(const PluginPackage& a, const PluginPackage& b) +{ + notImplemented(); + return false; +} + +int PluginPackage::compareFileVersion(const PlatformModuleVersion& compareVersion) const +{ + notImplemented(); + return 0; +} + +} diff --git a/WebCore/plugins/wx/PluginViewWx.cpp b/WebCore/plugins/wx/PluginViewWx.cpp new file mode 100644 index 0000000..834761c --- /dev/null +++ b/WebCore/plugins/wx/PluginViewWx.cpp @@ -0,0 +1,140 @@ +/* + * 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" + +#include "NotImplemented.h" +#include "PluginPackage.h" + +using namespace WTF; + +namespace WebCore { + +void PluginView::setFocus() +{ + notImplemented(); +} + +void PluginView::show() +{ + notImplemented(); +} + +void PluginView::hide() +{ + notImplemented(); +} + +void PluginView::paint(GraphicsContext* context, const IntRect& rect) +{ + notImplemented(); +} + +void PluginView::handleKeyboardEvent(KeyboardEvent* event) +{ + notImplemented(); +} + +void PluginView::handleMouseEvent(MouseEvent* event) +{ + notImplemented(); +} + +void PluginView::setParent(ScrollView* parent) +{ + notImplemented(); +} + +void PluginView::setNPWindowRect(const IntRect& rect) +{ + notImplemented(); +} + +void PluginView::stop() +{ + notImplemented(); +} + +const char* PluginView::userAgent() +{ + notImplemented(); + return 0; +} + +NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf) +{ + notImplemented(); + + return 0; +} + +NPError PluginView::getValue(NPNVariable variable, void* value) +{ + notImplemented(); + return 0; +} + +void PluginView::invalidateRect(NPRect* rect) +{ + notImplemented(); +} + +void PluginView::invalidateRect(const IntRect&) +{ + notImplemented(); +} + +void PluginView::invalidateRegion(NPRegion region) +{ + notImplemented(); +} + +void PluginView::forceRedraw() +{ + notImplemented(); +} + +PluginView::~PluginView() +{ + notImplemented(); +} + +void PluginView::init() +{ + notImplemented(); +} + +void PluginView::setParentVisible(bool) +{ + notImplemented(); +} + +void PluginView::updatePluginWidget() const +{ + notImplemented(); +} + +} // namespace WebCore |