- Add support for embedded netscape-style plugins.
- Add new webkit_glue VisitedLinkHash() and IsLinkVisited() functions required by underlying chromium changes.
cefclient:
- Add sample netscape-style plugin implementation and related Plugin item on the Tests menu.
- Increase the speed of the update timer so that buttons refresh closer to real-time.

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@5 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2008-12-14 04:49:18 +00:00
parent d0639c9f4e
commit a08ad505ad
31 changed files with 4417 additions and 12 deletions

View File

@ -10,3 +10,4 @@ Date | CEF Revision | Chromium Revision
2008-12-02 | /trunk@2 | /trunk@6213
2008-12-05 | /trunk@3 | /trunk@6430
2008-12-13 | /trunk@4 | /trunk@6968
2008-12-13 | /trunk@5 | /trunk@6975

76
include/cef_nplugin.h Normal file
View File

@ -0,0 +1,76 @@
// Copyright (c) 2008 Marshall A. Greenblatt. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the name Chromium Embedded
// Framework nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef _CEF_PLUGIN_H
#define _CEF_PLUGIN_H
#include <string>
#include "webkit/glue/plugins/nphostapi.h"
#include "third_party/npapi/bindings/npapi.h"
// Netscape plugins are normally built at separate DLLs that are loaded by the
// browser when needed. This interface supports the creation of plugins that
// are an embedded component of the application. Embedded plugins built using
// this interface use the same Netscape Plugin API as DLL-based plugins.
// See https://developer.mozilla.org/En/Gecko_Plugin_API_Reference for complete
// documentation on how to use the Netscape Plugin API.
// This structure fully describes a plugin.
struct CefPluginVersionInfo {
// Unique name used to identify a plugin. The unique name is used in place
// of the file path that would be available with normal plugin DLLs.
std::wstring unique_name;
std::wstring product_name;
std::wstring description;
std::wstring version;
// List of supported mime type values, delimited with a pipe (|) character.
std::wstring mime_types;
// List of supported file extensions, delimited with a pipe (|) character.
std::wstring file_extensions;
// List of descriptions for the file extensions, delimited with a pipe (|)
// character.
std::wstring file_open_names;
};
// This structure provides version information and entry point functions.
struct CefPluginInfo {
CefPluginVersionInfo version_info;
NP_GetEntryPointsFunc np_getentrypoints;
NP_InitializeFunc np_initialize;
NP_ShutdownFunc np_shutdown;
};
// Register the plugin with the system.
bool CefRegisterPlugin(const struct CefPluginInfo& plugin_info);
// Unregister the plugin with the system.
bool CefUnregisterPlugin(const struct CefPluginInfo& plugin_info);
#endif // _CEF_PLUGIN_H

View File

@ -150,4 +150,12 @@ std::string GetDocumentString(WebFrame* frame) {
return StringToStdString(WebCore::createMarkup(core_frame->document()));
}
uint64 VisitedLinkHash(const char* canonical_url, size_t length) {
return 0;
}
bool IsLinkVisited(uint64 link_hash) {
return false;
}
} // namespace webkit_glue

View File

@ -5,6 +5,7 @@
#include "precompiled_libcef.h"
#include "browser_webkit_glue.h"
#include "plugins/browser_plugin_list.h"
#include <atlcore.h>
#include <atlbase.h>
@ -45,7 +46,9 @@ HCURSOR LoadCursor(int cursor_id) {
}
bool GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) {
return NPAPI::PluginList::Singleton()->GetPlugins(refresh, plugins);
NPAPI::PluginList::Singleton()->GetPlugins(refresh, plugins);
NPAPI::BrowserPluginList::Singleton()->GetPlugins(refresh, plugins);
return true;
}
bool EnsureFontLoaded(HFONT font) {

View File

@ -14,6 +14,8 @@
#include "browser_navigation_controller.h"
#include "browser_impl.h"
#include "context.h"
#include "plugins/browser_webplugin_delegate_impl.h"
#include "plugins/browser_plugin_list.h"
#include <objidl.h>
#include <shlobj.h>
@ -55,16 +57,33 @@ WebPluginDelegate* BrowserWebViewDelegate::CreatePluginDelegate(
return NULL;
bool allow_wildcard = true;
WebPluginInfo info;
if (!NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, clsid,
allow_wildcard, &info,
actual_mime_type))
return NULL;
if (actual_mime_type && !actual_mime_type->empty())
return WebPluginDelegateImpl::Create(info.file, *actual_mime_type, hwnd);
else
return WebPluginDelegateImpl::Create(info.file, mime_type, hwnd);
// first, look for plugins using the normal plugin list
WebPluginInfo info;
if (NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, clsid,
allow_wildcard, &info,
actual_mime_type)) {
if (actual_mime_type && !actual_mime_type->empty())
return WebPluginDelegateImpl::Create(info.file, *actual_mime_type, hwnd);
else
return WebPluginDelegateImpl::Create(info.file, mime_type, hwnd);
}
// second, look for plugins using the embedded plugin list
CefPluginInfo plugin_info;
if (NPAPI::BrowserPluginList::Singleton()->GetPluginInfo(url, mime_type,
clsid,
allow_wildcard,
&plugin_info,
actual_mime_type)) {
if (actual_mime_type && !actual_mime_type->empty())
return BrowserWebPluginDelegateImpl::Create(plugin_info,
*actual_mime_type, hwnd);
else
return BrowserWebPluginDelegateImpl::Create(plugin_info, mime_type, hwnd);
}
return NULL;
}
void BrowserWebViewDelegate::Show(WebWidget* webwidget, WindowOpenDisposition) {

View File

@ -8,6 +8,7 @@
#include "browser_impl.h"
#include "browser_resource_loader_bridge.h"
#include "browser_request_context.h"
#include "plugins/browser_plugin_list.h"
#include "base/at_exit.h"
#include "base/icu_util.h"
@ -52,6 +53,48 @@ void CefShutdown()
_Context = NULL;
}
bool CefRegisterPlugin(const struct CefPluginInfo& plugin_info)
{
if(!_Context.get())
return false;
CefPluginInfo* pPluginInfo = new CefPluginInfo;
*pPluginInfo = plugin_info;
PostTask(FROM_HERE, NewRunnableMethod(_Context.get(),
&CefContext::UIT_RegisterPlugin, pPluginInfo));
return true;
}
void CefContext::UIT_RegisterPlugin(struct CefPluginInfo* plugin_info)
{
REQUIRE_UIT();
NPAPI::BrowserPluginList::Singleton()->AddPlugin(*plugin_info);
delete plugin_info;
}
// Unregister the plugin with the system.
bool CefUnregisterPlugin(const struct CefPluginInfo& plugin_info)
{
if(!_Context.get())
return false;
CefPluginInfo* pPluginInfo = new CefPluginInfo;
*pPluginInfo = plugin_info;
PostTask(FROM_HERE, NewRunnableMethod(_Context.get(),
&CefContext::UIT_UnregisterPlugin, pPluginInfo));
return true;
}
void CefContext::UIT_UnregisterPlugin(struct CefPluginInfo* plugin_info)
{
REQUIRE_UIT();
NPAPI::BrowserPluginList::Singleton()->RemovePlugin(*plugin_info);
delete plugin_info;
}
StringPiece GetRawDataResource(HMODULE module, int resource_id) {
void* data_ptr;

View File

@ -38,6 +38,13 @@ public:
// Returns true if the calling thread is the same as the UI thread
bool RunningOnUIThread() { return (GetCurrentThreadId() == idthreadui_); }
////////////////////////////////////////////////////////////
// ALL UIT_* METHODS MUST ONLY BE CALLED ON THE UI THREAD //
////////////////////////////////////////////////////////////
void UIT_RegisterPlugin(struct CefPluginInfo* plugin_info);
void UIT_UnregisterPlugin(struct CefPluginInfo* plugin_info);
private:
void SetMessageLoopForUI(MessageLoopForUI* loop);
void NotifyEvent();

View File

@ -184,6 +184,10 @@
RelativePath="..\include\cef.h"
>
</File>
<File
RelativePath="..\include\cef_nplugin.h"
>
</File>
<File
RelativePath="..\include\cef_ptr.h"
>
@ -193,6 +197,78 @@
>
</File>
</Filter>
<Filter
Name="plugins"
>
<File
RelativePath=".\plugins\browser_mozilla_extensions.cc"
>
</File>
<File
RelativePath=".\plugins\browser_mozilla_extensions.h"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_instance.cc"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_instance.h"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_lib.cc"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_lib.h"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_list.cc"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_list.h"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_stream.cc"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_stream.h"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_stream_url.cc"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_stream_url.h"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_stream_win.cc"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_string_stream.cc"
>
</File>
<File
RelativePath=".\plugins\browser_plugin_string_stream.h"
>
</File>
<File
RelativePath=".\plugins\browser_webplugin_delegate_impl.cc"
>
</File>
<File
RelativePath=".\plugins\browser_webplugin_delegate_impl.h"
>
</File>
</Filter>
<File
RelativePath=".\browser_drag_delegate.cc"
>

View File

@ -0,0 +1,373 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "precompiled_libcef.h"
#include "browser_mozilla_extensions.h"
#include "browser_plugin_instance.h"
#include <algorithm>
#include "base/logging.h"
#include "base/string_util.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
#include "net/proxy/proxy_service.h"
#include "net/proxy/proxy_resolver_winhttp.h"
#include "third_party/npapi/bindings/npapi.h"
#include "webkit/glue/webkit_glue.h"
#define QI_SUPPORTS_IID(iid, iface) \
QI_SUPPORTS_IID_(iid, iface::GetIID(), iface)
#define QI_SUPPORTS_IID_(src_iid, iface_iid, iface) \
if (iid.Equals(iface_iid)) { \
AddRef(); \
*result = static_cast<iface*>(this); \
return NS_OK; \
}
namespace NPAPI
{
void BrowserMozillaExtensionApi::DetachFromInstance() {
plugin_instance_ = NULL;
}
bool BrowserMozillaExtensionApi::FindProxyForUrl(const char* url,
std::string* proxy) {
bool result = false;
if ((!url) || (!proxy)) {
NOTREACHED();
return result;
}
scoped_ptr<net::ProxyService> proxy_service(net::ProxyService::Create(NULL));
if (!proxy_service.get()) {
NOTREACHED();
return result;
}
net::ProxyInfo proxy_info;
if (proxy_service->ResolveProxy(GURL(std::string(url)),
&proxy_info,
NULL,
NULL) == net::OK) {
if (!proxy_info.is_direct()) {
std::string winhttp_proxy = proxy_info.proxy_server();
// Winhttp returns proxy in the the following format:
// - HTTP proxy: "111.111.111.111:11"
// -.SOCKS proxy: "socks=111.111.111.111:11"
// - Mixed proxy: "http=111.111.111.111:11; socks=222.222.222.222:22"
//
// We need to translate this into the following format:
// i) "DIRECT" -- no proxy
// ii) "PROXY xxx.xxx.xxx.xxx" -- use proxy
// iii) "SOCKS xxx.xxx.xxx.xxx" -- use SOCKS
// iv) Mixed. e.g. "PROXY 111.111.111.111;PROXY 112.112.112.112",
// "PROXY 111.111.111.111;SOCKS 112.112.112.112"....
StringToLowerASCII(winhttp_proxy);
if (std::string::npos == winhttp_proxy.find('=')) {
// Proxy is in the form: "111.111.111.111:11"
winhttp_proxy.insert(0, "http ");
} else {
// Proxy is in the following form.
// -.SOCKS proxy: "socks=111.111.111.111:11"
// - Mixed proxy: "http=111.111.111.111:11; socks=222.222.222.222:22"
// in this case just replace the '=' with a space
std::replace_if(winhttp_proxy.begin(),
winhttp_proxy.end(),
std::bind2nd(std::equal_to<char>(), '='), ' ');
}
*proxy = winhttp_proxy;
result = true;
}
}
return result;
}
// nsISupports implementation
NS_IMETHODIMP BrowserMozillaExtensionApi::QueryInterface(REFNSIID iid,
void** result) {
static const nsIID knsISupportsIID = NS_ISUPPORTS_IID;
QI_SUPPORTS_IID_(iid, knsISupportsIID, nsIServiceManager)
QI_SUPPORTS_IID(iid, nsIServiceManager)
QI_SUPPORTS_IID(iid, nsIPluginManager)
QI_SUPPORTS_IID(iid, nsIPluginManager2)
QI_SUPPORTS_IID(iid, nsICookieStorage)
NOTREACHED();
return NS_ERROR_NO_INTERFACE;
}
NS_IMETHODIMP_(nsrefcnt) BrowserMozillaExtensionApi::AddRef(void) {
return InterlockedIncrement(reinterpret_cast<LONG*>(&ref_count_));
}
NS_IMETHODIMP_(nsrefcnt) BrowserMozillaExtensionApi::Release(void) {
DCHECK(static_cast<int>(ref_count_) > 0);
if (InterlockedDecrement(reinterpret_cast<LONG*>(&ref_count_)) == 0) {
delete this;
return 0;
}
return ref_count_;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::GetService(REFNSIID class_guid,
REFNSIID iid,
void** result) {
static const nsIID kPluginManagerCID = NS_PLUGINMANAGER_CID;
static const nsIID kCookieStorageCID = NS_COOKIESTORAGE_CID;
nsresult rv = NS_ERROR_FAILURE;
if ((class_guid.Equals(kPluginManagerCID)) ||
(class_guid.Equals(kCookieStorageCID))) {
rv = QueryInterface(iid, result);
}
DCHECK(rv == NS_OK);
return rv;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::GetServiceByContractID(
const char* contract_id,
REFNSIID iid,
void** result) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::IsServiceInstantiated(REFNSIID class_guid,
REFNSIID iid,
PRBool* result) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::IsServiceInstantiatedByContractID(
const char* contract_id,
REFNSIID iid,
PRBool* result) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::GetValue(nsPluginManagerVariable variable,
void * value) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::ReloadPlugins(PRBool reloadPages) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::UserAgent(
const char** resultingAgentString) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::GetURL(
nsISupports* pluginInst,
const char* url,
const char* target,
nsIPluginStreamListener* streamListener,
const char* altHost,
const char* referrer,
PRBool forceJSEnabled) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::PostURL(
nsISupports* pluginInst,
const char* url,
unsigned int postDataLen,
const char* postData,
PRBool isFile,
const char* target,
nsIPluginStreamListener* streamListener,
const char* altHost,
const char* referrer,
PRBool forceJSEnabled ,
unsigned int postHeadersLength,
const char* postHeaders) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::RegisterPlugin(
REFNSIID aCID,
const char *aPluginName,
const char *aDescription,
const char * * aMimeTypes,
const char * * aMimeDescriptions,
const char * * aFileExtensions,
PRInt32 aCount) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::UnregisterPlugin(REFNSIID aCID) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::GetURLWithHeaders(
nsISupports* pluginInst,
const char* url,
const char* target /* = NULL */,
nsIPluginStreamListener* streamListener /* = NULL */,
const char* altHost /* = NULL */,
const char* referrer /* = NULL */,
PRBool forceJSEnabled /* = PR_FALSE */,
PRUint32 getHeadersLength /* = 0 */,
const char* getHeaders /* = NULL */){
NOTREACHED();
return NS_ERROR_FAILURE;
}
// nsIPluginManager2
NS_IMETHODIMP BrowserMozillaExtensionApi::BeginWaitCursor() {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::EndWaitCursor() {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::SupportsURLProtocol(const char* aProtocol,
PRBool* aResult) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::NotifyStatusChange(nsIPlugin* aPlugin,
nsresult aStatus) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::FindProxyForURL(
const char* aURL,
char** aResult) {
std::string proxy = "DIRECT";
FindProxyForUrl(aURL, &proxy);
// Allocate this using the NPAPI allocator. The plugin will call
// NPN_Free to free this.
char* result = static_cast<char*>(NPN_MemAlloc(proxy.length() + 1));
strncpy(result, proxy.c_str(), proxy.length() + 1);
*aResult = result;
return NS_OK;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::RegisterWindow(
nsIEventHandler* handler,
nsPluginPlatformWindowRef window) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::UnregisterWindow(
nsIEventHandler* handler,
nsPluginPlatformWindowRef win) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::AllocateMenuID(nsIEventHandler* aHandler,
PRBool aIsSubmenu,
PRInt16 *aResult) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::DeallocateMenuID(nsIEventHandler* aHandler,
PRInt16 aMenuID) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::HasAllocatedMenuID(nsIEventHandler* aHandler,
PRInt16 aMenuID,
PRBool* aResult) {
NOTREACHED();
return NS_ERROR_FAILURE;
}
// nsICookieStorage
NS_IMETHODIMP BrowserMozillaExtensionApi::GetCookie(
const char* url,
void* cookie_buffer,
PRUint32& buffer_size) {
if ((!url) || (!cookie_buffer)) {
return NS_ERROR_INVALID_ARG;
}
if (!plugin_instance_)
return NS_ERROR_FAILURE;
WebPlugin* webplugin = plugin_instance_->webplugin();
if (!webplugin)
return NS_ERROR_FAILURE;
// Bypass third-party cookie blocking by using the url as the policy_url.
GURL cookies_url((std::string(url)));
std::string cookies = webplugin->GetCookies(cookies_url, cookies_url);
if (cookies.empty())
return NS_ERROR_FAILURE;
if(cookies.length() >= buffer_size)
return NS_ERROR_FAILURE;
strncpy(static_cast<char*>(cookie_buffer),
cookies.c_str(),
cookies.length() + 1);
buffer_size = cookies.length();
return NS_OK;
}
NS_IMETHODIMP BrowserMozillaExtensionApi::SetCookie(
const char* url,
const void* cookie_buffer,
PRUint32 buffer_size){
if ((!url) || (!cookie_buffer) || (!buffer_size)) {
return NS_ERROR_INVALID_ARG;
}
if (!plugin_instance_)
return NS_ERROR_FAILURE;
WebPlugin* webplugin = plugin_instance_->webplugin();
if (!webplugin)
return NS_ERROR_FAILURE;
std::string cookie(static_cast<const char*>(cookie_buffer),
buffer_size);
GURL cookies_url((std::string(url)));
webplugin->SetCookie(cookies_url,
cookies_url,
cookie);
return NS_OK;
}
} // namespace NPAPI

View File

@ -0,0 +1,101 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _BROWSER_MOZILLA_EXTENSIONS_H
#define _BROWSER_MOZILLA_EXTENSIONS_H
#include <string>
// Include npapi first to avoid definition clashes due to
// XP_WIN
#include "third_party/npapi/bindings/npapi.h"
#include "third_party/mozilla/include/nsIServiceManager.h"
#include "third_party/mozilla/include/nsIPluginManager2.h"
#include "third_party/mozilla/include/nsICookieStorage.h"
#include "third_party/mozilla/include/nsError.h"
#include "base/ref_counted.h"
// NS_DECL_NSIPLUGINMANAGER doesn't include methods described as "C++" in the
// nsIPluginManager.idl.
#define NS_DECL_NSIPLUGINMANAGER_FIXED \
NS_DECL_NSIPLUGINMANAGER \
NS_IMETHOD \
GetURL(nsISupports* pluginInst, \
const char* url, \
const char* target = NULL, \
nsIPluginStreamListener* streamListener = NULL, \
const char* altHost = NULL, \
const char* referrer = NULL, \
PRBool forceJSEnabled = PR_FALSE); \
NS_IMETHOD \
PostURL(nsISupports* pluginInst, \
const char* url, \
PRUint32 postDataLen, \
const char* postData, \
PRBool isFile = PR_FALSE, \
const char* target = NULL, \
nsIPluginStreamListener* streamListener = NULL, \
const char* altHost = NULL, \
const char* referrer = NULL, \
PRBool forceJSEnabled = PR_FALSE, \
PRUint32 postHeadersLength = 0, \
const char* postHeaders = NULL); \
NS_IMETHOD \
GetURLWithHeaders(nsISupports* pluginInst, \
const char* url, \
const char* target = NULL, \
nsIPluginStreamListener* streamListener = NULL, \
const char* altHost = NULL, \
const char* referrer = NULL, \
PRBool forceJSEnabled = PR_FALSE, \
PRUint32 getHeadersLength = 0, \
const char* getHeaders = NULL);
// Avoid dependence on the nsIsupportsImpl.h and so on.
#ifndef NS_DECL_ISUPPORTS
#define NS_DECL_ISUPPORTS \
NS_IMETHOD QueryInterface(REFNSIID aIID, \
void** aInstancePtr); \
NS_IMETHOD_(nsrefcnt) AddRef(void); \
NS_IMETHOD_(nsrefcnt) Release(void);
#endif // NS_DECL_ISUPPORTS
namespace NPAPI
{
class BrowserPluginInstance;
// Implementation of extended Mozilla interfaces needed to support
// Sun's new Java plugin.
class BrowserMozillaExtensionApi : public nsIServiceManager,
public nsIPluginManager2,
public nsICookieStorage {
public:
BrowserMozillaExtensionApi(BrowserPluginInstance* plugin_instance) :
plugin_instance_(plugin_instance), ref_count_(0) {
}
void DetachFromInstance();
NS_DECL_ISUPPORTS
NS_DECL_NSISERVICEMANAGER
NS_DECL_NSIPLUGINMANAGER_FIXED
NS_DECL_NSIPLUGINMANAGER2
NS_DECL_NSICOOKIESTORAGE
protected:
bool FindProxyForUrl(const char* url, std::string* proxy);
protected:
scoped_refptr<NPAPI::BrowserPluginInstance> plugin_instance_;
unsigned long ref_count_;
};
} // namespace NPAPI
#endif // _BROWSER_MOZILLA_EXTENSIONS_H

View File

@ -0,0 +1,512 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "precompiled_libcef.h"
#include "browser_plugin_instance.h"
#include "browser_plugin_lib.h"
#include "browser_plugin_stream_url.h"
#include "browser_plugin_string_stream.h"
#if defined(OS_WIN)
#include "browser_mozilla_extensions.h"
#endif
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread_local_storage.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webplugin.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/plugins/plugin_host.h"
#include "net/base/escape.h"
namespace NPAPI
{
// TODO(evanm): don't rely on static initialization.
ThreadLocalStorage::Slot BrowserPluginInstance::plugin_instance_tls_index_;
BrowserPluginInstance::BrowserPluginInstance(BrowserPluginLib *plugin,
const std::string &mime_type)
: plugin_(plugin),
npp_(0),
host_(PluginHost::Singleton()),
npp_functions_(plugin->functions()),
#if defined(OS_WIN)
hwnd_(0),
#endif
windowless_(false),
transparent_(true),
webplugin_(0),
mime_type_(mime_type),
get_notify_data_(NULL),
use_mozilla_user_agent_(false),
message_loop_(MessageLoop::current()),
load_manually_(false),
in_close_streams_(false) {
npp_ = new NPP_t();
npp_->ndata = 0;
npp_->pdata = 0;
memset(&zero_padding_, 0, sizeof(zero_padding_));
DCHECK(message_loop_);
}
BrowserPluginInstance::~BrowserPluginInstance() {
CloseStreams();
if (npp_ != 0) {
delete npp_;
npp_ = 0;
}
if (plugin_)
plugin_->CloseInstance();
}
BrowserPluginStreamUrl *BrowserPluginInstance::CreateStream(int resource_id,
const std::string &url,
const std::string &mime_type,
bool notify_needed,
void *notify_data) {
BrowserPluginStreamUrl *stream = new BrowserPluginStreamUrl(
resource_id, GURL(url), this, notify_needed, notify_data);
AddStream(stream);
return stream;
}
void BrowserPluginInstance::AddStream(BrowserPluginStream* stream) {
open_streams_.push_back(stream);
}
void BrowserPluginInstance::RemoveStream(BrowserPluginStream* stream) {
if (in_close_streams_)
return;
std::vector<scoped_refptr<BrowserPluginStream> >::iterator stream_index;
for (stream_index = open_streams_.begin();
stream_index != open_streams_.end(); ++stream_index) {
if (*stream_index == stream) {
open_streams_.erase(stream_index);
break;
}
}
}
bool BrowserPluginInstance::IsValidStream(const NPStream* stream) {
std::vector<scoped_refptr<BrowserPluginStream> >::iterator stream_index;
for (stream_index = open_streams_.begin();
stream_index != open_streams_.end(); ++stream_index) {
if ((*stream_index)->stream() == stream)
return true;
}
return false;
}
void BrowserPluginInstance::CloseStreams() {
in_close_streams_ = true;
for (unsigned int index = 0; index < open_streams_.size(); ++index) {
// Close all streams on the way down.
open_streams_[index]->Close(NPRES_USER_BREAK);
}
open_streams_.clear();
in_close_streams_ = false;
}
#if defined(OS_WIN)
bool BrowserPluginInstance::HandleEvent(UINT message, WPARAM wParam, LPARAM lParam) {
if (!windowless_)
return false;
NPEvent windowEvent;
windowEvent.event = message;
windowEvent.lParam = static_cast<uint32>(lParam);
windowEvent.wParam = static_cast<uint32>(wParam);
return NPP_HandleEvent(&windowEvent) != 0;
}
#endif
bool BrowserPluginInstance::Start(const GURL& url,
char** const param_names,
char** const param_values,
int param_count,
bool load_manually) {
load_manually_ = load_manually;
instance_url_ = url;
unsigned short mode = load_manually_ ? NP_FULL : NP_EMBED;
npp_->ndata = this;
NPError err = NPP_New(mode, param_count,
const_cast<char **>(param_names), const_cast<char **>(param_values));
return err == NPERR_NO_ERROR;
}
NPObject *BrowserPluginInstance::GetPluginScriptableObject() {
NPObject *value = NULL;
NPError error = NPP_GetValue(NPPVpluginScriptableNPObject, &value);
if (error != NPERR_NO_ERROR || value == NULL)
return NULL;
return value;
}
void BrowserPluginInstance::SetURLLoadData(const GURL& url,
void* notify_data) {
get_url_ = url;
get_notify_data_ = notify_data;
}
// WebPluginLoadDelegate methods
void BrowserPluginInstance::DidFinishLoadWithReason(NPReason reason) {
if (!get_url_.is_empty()) {
NPP_URLNotify(get_url_.spec().c_str(), reason, get_notify_data_);
}
get_url_ = GURL();
get_notify_data_ = NULL;
}
// NPAPI methods
NPError BrowserPluginInstance::NPP_New(unsigned short mode,
short argc,
char *argn[],
char *argv[]) {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->newp != 0);
DCHECK(argc >= 0);
if (npp_functions_->newp != 0) {
return npp_functions_->newp(
(NPMIMEType)mime_type_.c_str(), npp_, mode, argc, argn, argv, NULL);
}
return NPERR_INVALID_FUNCTABLE_ERROR;
}
void BrowserPluginInstance::NPP_Destroy() {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->newp != 0);
if (npp_functions_->destroy != 0) {
NPSavedData *savedData = 0;
npp_functions_->destroy(npp_, &savedData);
// TODO: Support savedData. Technically, these need to be
// saved on a per-URL basis, and then only passed
// to new instances of the plugin at the same URL.
// Sounds like a huge security risk. When we do support
// these, we should pass them back to the PluginLib
// to be stored there.
DCHECK(savedData == 0);
}
#if defined(OS_WIN)
// Clean up back references to this instance if any
if (mozilla_extenstions_) {
mozilla_extenstions_->DetachFromInstance();
mozilla_extenstions_ = NULL;
}
#endif
for (unsigned int file_index = 0; file_index < files_created_.size();
file_index++) {
file_util::Delete(files_created_[file_index], false);
}
}
NPError BrowserPluginInstance::NPP_SetWindow(NPWindow *window) {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->setwindow != 0);
if (npp_functions_->setwindow != 0) {
return npp_functions_->setwindow(npp_, window);
}
return NPERR_INVALID_FUNCTABLE_ERROR;
}
NPError BrowserPluginInstance::NPP_NewStream(NPMIMEType type,
NPStream *stream,
NPBool seekable,
unsigned short *stype) {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->newstream != 0);
if (npp_functions_->newstream != 0) {
return npp_functions_->newstream(npp_, type, stream, seekable, stype);
}
return NPERR_INVALID_FUNCTABLE_ERROR;
}
NPError BrowserPluginInstance::NPP_DestroyStream(NPStream *stream,
NPReason reason) {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->destroystream != 0);
if (stream == NULL || (stream->ndata == NULL) ||
!IsValidStream(stream))
return NPERR_INVALID_INSTANCE_ERROR;
if (npp_functions_->destroystream != 0) {
NPError result = npp_functions_->destroystream(npp_, stream, reason);
stream->ndata = NULL;
return result;
}
return NPERR_INVALID_FUNCTABLE_ERROR;
}
int BrowserPluginInstance::NPP_WriteReady(NPStream *stream) {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->writeready != 0);
if (npp_functions_->writeready != 0) {
return npp_functions_->writeready(npp_, stream);
}
return NULL;
}
int BrowserPluginInstance::NPP_Write(NPStream *stream,
int offset,
int len,
void *buffer) {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->write != 0);
if (npp_functions_->write != 0) {
return npp_functions_->write(npp_, stream, offset, len, buffer);
}
return NULL;
}
void BrowserPluginInstance::NPP_StreamAsFile(NPStream *stream,
const char *fname) {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->asfile != 0);
if (npp_functions_->asfile != 0) {
npp_functions_->asfile(npp_, stream, fname);
}
// Creating a temporary FilePath instance on the stack as the explicit
// FilePath constructor with StringType as an argument causes a compiler
// error when invoked via vector push back.
FilePath file_name(UTF8ToWide(fname));
files_created_.push_back(file_name);
}
void BrowserPluginInstance::NPP_URLNotify(const char *url,
NPReason reason,
void *notifyData) {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->urlnotify != 0);
if (npp_functions_->urlnotify != 0) {
npp_functions_->urlnotify(npp_, url, reason, notifyData);
}
}
NPError BrowserPluginInstance::NPP_GetValue(NPPVariable variable, void *value) {
DCHECK(npp_functions_ != 0);
// getvalue is NULL for Shockwave
if (npp_functions_->getvalue != 0) {
return npp_functions_->getvalue(npp_, variable, value);
}
return NPERR_INVALID_FUNCTABLE_ERROR;
}
NPError BrowserPluginInstance::NPP_SetValue(NPNVariable variable, void *value) {
DCHECK(npp_functions_ != 0);
if (npp_functions_->setvalue != 0) {
return npp_functions_->setvalue(npp_, variable, value);
}
return NPERR_INVALID_FUNCTABLE_ERROR;
}
short BrowserPluginInstance::NPP_HandleEvent(NPEvent *event) {
DCHECK(npp_functions_ != 0);
DCHECK(npp_functions_->event != 0);
if (npp_functions_->event != 0) {
return npp_functions_->event(npp_, (void*)event);
}
return false;
}
bool BrowserPluginInstance::NPP_Print(NPPrint* platform_print) {
DCHECK(npp_functions_ != 0);
if (npp_functions_->print != 0) {
npp_functions_->print(npp_, platform_print);
return true;
}
return false;
}
void BrowserPluginInstance::SendJavaScriptStream(const std::string& url,
const std::wstring& result,
bool success,
bool notify_needed,
int notify_data) {
if (success) {
BrowserPluginStringStream *stream =
new BrowserPluginStringStream(this, url, notify_needed,
reinterpret_cast<void*>(notify_data));
AddStream(stream);
stream->SendToPlugin(WideToUTF8(result), "text/html");
} else {
// NOTE: Sending an empty stream here will crash MacroMedia
// Flash 9. Just send the URL Notify.
if (notify_needed) {
this->NPP_URLNotify(url.c_str(), NPRES_DONE,
reinterpret_cast<void*>(notify_data));
}
}
}
void BrowserPluginInstance::DidReceiveManualResponse(const std::string& url,
const std::string& mime_type,
const std::string& headers,
uint32 expected_length,
uint32 last_modified) {
DCHECK(load_manually_);
std::string response_url = url;
if (response_url.empty()) {
response_url = instance_url_.spec();
}
bool cancel = false;
plugin_data_stream_ = CreateStream(-1, url, mime_type, false, NULL);
plugin_data_stream_->DidReceiveResponse(mime_type, headers, expected_length,
last_modified, &cancel);
AddStream(plugin_data_stream_.get());
}
void BrowserPluginInstance::DidReceiveManualData(const char* buffer,
int length) {
DCHECK(load_manually_);
if (plugin_data_stream_.get() != NULL) {
plugin_data_stream_->DidReceiveData(buffer, length, 0);
}
}
void BrowserPluginInstance::DidFinishManualLoading() {
DCHECK(load_manually_);
if (plugin_data_stream_.get() != NULL) {
plugin_data_stream_->DidFinishLoading();
plugin_data_stream_->Close(NPRES_DONE);
plugin_data_stream_ = NULL;
}
}
void BrowserPluginInstance::DidManualLoadFail() {
DCHECK(load_manually_);
if (plugin_data_stream_.get() != NULL) {
plugin_data_stream_->DidFail();
plugin_data_stream_ = NULL;
}
}
void BrowserPluginInstance::PluginThreadAsyncCall(void (*func)(void *),
void *userData) {
message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
this, &BrowserPluginInstance::OnPluginThreadAsyncCall, func, userData));
}
void BrowserPluginInstance::OnPluginThreadAsyncCall(void (*func)(void *),
void *userData) {
#if defined(OS_WIN)
// We are invoking an arbitrary callback provided by a third
// party plugin. It's better to wrap this into an exception
// block to protect us from crashes.
__try {
func(userData);
} __except(EXCEPTION_EXECUTE_HANDLER) {
// Maybe we can disable a crashing plugin.
// But for now, just continue.
}
#else
NOTIMPLEMENTED();
#endif
}
BrowserPluginInstance* BrowserPluginInstance::SetInitializingInstance(
BrowserPluginInstance* instance) {
BrowserPluginInstance* old_instance =
static_cast<BrowserPluginInstance*>(plugin_instance_tls_index_.Get());
plugin_instance_tls_index_.Set(instance);
return old_instance;
}
BrowserPluginInstance* BrowserPluginInstance::GetInitializingInstance() {
BrowserPluginInstance* instance =
static_cast<BrowserPluginInstance*>(plugin_instance_tls_index_.Get());
return instance;
}
NPError BrowserPluginInstance::GetServiceManager(void** service_manager) {
#if defined(OS_WIN)
if (!mozilla_extenstions_) {
mozilla_extenstions_ = new BrowserMozillaExtensionApi(this);
}
DCHECK(mozilla_extenstions_);
mozilla_extenstions_->QueryInterface(nsIServiceManager::GetIID(),
service_manager);
#else
NOTIMPLEMENTED();
#endif
return NPERR_NO_ERROR;
}
void BrowserPluginInstance::PushPopupsEnabledState(bool enabled) {
popups_enabled_stack_.push(enabled);
}
void BrowserPluginInstance::PopPopupsEnabledState() {
popups_enabled_stack_.pop();
}
void BrowserPluginInstance::RequestRead(NPStream* stream,
NPByteRange* range_list) {
std::string range_info = "bytes=";
while (range_list) {
range_info += IntToString(range_list->offset);
range_info += "-";
range_info += IntToString(range_list->offset + range_list->length - 1);
range_list = range_list->next;
if (range_list) {
range_info += ",";
}
}
if (plugin_data_stream_) {
if (plugin_data_stream_->stream() == stream) {
webplugin_->CancelDocumentLoad();
plugin_data_stream_ = NULL;
}
}
// The lifetime of a NPStream instance depends on the BrowserPluginStream
// instance which owns it. When a plugin invokes NPN_RequestRead on a seekable
// stream, we don't want to create a new stream when the corresponding
// response is received. We send over a cookie which represents the
// BrowserPluginStream instance which is sent back from the renderer when the
// response is received.
std::vector<scoped_refptr<BrowserPluginStream> >::iterator stream_index;
for (stream_index = open_streams_.begin();
stream_index != open_streams_.end(); ++stream_index) {
BrowserPluginStream* plugin_stream = *stream_index;
if (plugin_stream->stream() == stream) {
// A stream becomes seekable the first time NPN_RequestRead
// is called on it.
plugin_stream->set_seekable(true);
webplugin_->InitiateHTTPRangeRequest(
stream->url, range_info.c_str(),
plugin_stream,
plugin_stream->notify_needed(),
plugin_stream->notify_data());
break;
}
}
}
} // namespace NPAPI

View File

@ -0,0 +1,268 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO: Need to deal with NPAPI's NPSavedData.
// I haven't seen plugins use it yet.
#ifndef _BROWSER_PLUGIN_INSTANCE_H
#define _BROWSER_PLUGIN_INSTANCE_H
#include <string>
#include <vector>
#include <stack>
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/thread_local_storage.h"
#include "webkit/glue/plugins/nphostapi.h"
#include "googleurl/src/gurl.h"
#include "third_party/npapi/bindings/npapi.h"
class WebPlugin;
class MessageLoop;
namespace NPAPI
{
class BrowserPluginLib;
class BrowserPluginStream;
class BrowserPluginStreamUrl;
class BrowserPluginDataStream;
class BrowserMozillaExtensionApi;
class PluginHost;
// A BrowserPluginInstance is an active, running instance of a Plugin.
// A single plugin may have many BrowserPluginInstances.
class BrowserPluginInstance : public base::RefCountedThreadSafe<BrowserPluginInstance> {
public:
// Create a new instance of a plugin. The BrowserPluginInstance
// will hold a reference to the plugin.
BrowserPluginInstance(BrowserPluginLib *plugin, const std::string &mime_type);
virtual ~BrowserPluginInstance();
// Activates the instance by calling NPP_New.
// This should be called after our instance is all
// setup from the host side and we are ready to receive
// requests from the plugin. We must not call any
// functions on the plugin instance until start has
// been called.
//
// url: The instance URL.
// param_names: the list of names of attributes passed via the
// element.
// param_values: the list of values corresponding to param_names
// param_count: number of attributes
// load_manually: if true indicates that the plugin data would be passed
// from webkit. if false indicates that the plugin should
// download the data.
// This also controls whether the plugin is instantiated as
// a full page plugin (NP_FULL) or embedded (NP_EMBED)
//
bool Start(const GURL& url,
char** const param_names,
char** const param_values,
int param_count,
bool load_manually);
// NPAPI's instance identifier for this instance
NPP npp() { return npp_; }
#if defined(OS_WIN)
// Get/Set for the instance's HWND.
HWND window_handle() { return hwnd_; }
void set_window_handle(HWND value) { hwnd_ = value; }
#endif
// Get/Set whether this instance is in Windowless mode.
// Default is false.
bool windowless() { return windowless_; }
void set_windowless(bool value) { windowless_ = value; }
// Get/Set whether this instance is transparent.
// This only applies to windowless plugins. Transparent
// plugins require that webkit paint the background.
// Default is true.
bool transparent() { return transparent_; }
void set_transparent(bool value) { transparent_ = value; }
// Get/Set the WebPlugin associated with this instance
WebPlugin* webplugin() { return webplugin_; }
void set_web_plugin(WebPlugin* webplugin) { webplugin_ = webplugin; }
// Get the mimeType for this plugin stream
const std::string &mime_type() { return mime_type_; }
NPAPI::BrowserPluginLib* plugin_lib() { return plugin_; }
#if defined(OS_WIN)
// Handles a windows native message which this BrowserPluginInstance should deal
// with. Returns true if the event is handled, false otherwise.
bool HandleEvent(UINT message, WPARAM wParam, LPARAM lParam);
#endif
// Creates a stream for sending an URL. If notify_needed
// is true, it will send a notification to the plugin
// when the stream is complete; otherwise it will not.
// Set object_url to true if the load is for the object tag's
// url, or false if it's for a url that the plugin
// fetched through NPN_GetUrl[Notify].
BrowserPluginStreamUrl *CreateStream(int resource_id,
const std::string &url,
const std::string &mime_type,
bool notify_needed,
void *notify_data);
// For each instance, we track all streams. When the
// instance closes, all remaining streams are also
// closed. All streams associated with this instance
// should call AddStream so that they can be cleaned
// up when the instance shuts down.
void AddStream(BrowserPluginStream* stream);
// This is called when a stream is closed. We remove the stream from the
// list, which releases the reference maintained to the stream.
void RemoveStream(BrowserPluginStream* stream);
// Closes all open streams on this instance.
void CloseStreams();
// Have the plugin create it's script object.
NPObject *GetPluginScriptableObject();
// WebViewDelegate methods that we implement. This is for handling
// callbacks during getURLNotify.
virtual void DidFinishLoadWithReason(NPReason reason);
// Helper method to set some persistent data for getURLNotify since
// resource fetches happen async.
void SetURLLoadData(const GURL& url, void* notify_data);
// If true, send the Mozilla user agent instead of Chrome's to the plugin.
bool use_mozilla_user_agent() { return use_mozilla_user_agent_; }
void set_use_mozilla_user_agent() { use_mozilla_user_agent_ = true; }
// Helper that implements NPN_PluginThreadAsyncCall semantics
void PluginThreadAsyncCall(void (*func)(void *),
void *userData);
//
// NPAPI methods for calling the Plugin Instance
//
NPError NPP_New(unsigned short, short, char *[], char *[]);
NPError NPP_SetWindow(NPWindow *);
NPError NPP_NewStream(NPMIMEType, NPStream *, NPBool, unsigned short *);
NPError NPP_DestroyStream(NPStream *, NPReason);
int NPP_WriteReady(NPStream *);
int NPP_Write(NPStream *, int, int, void *);
void NPP_StreamAsFile(NPStream *, const char *);
void NPP_URLNotify(const char *, NPReason, void *);
NPError NPP_GetValue(NPPVariable, void *);
NPError NPP_SetValue(NPNVariable, void *);
short NPP_HandleEvent(NPEvent *);
void NPP_Destroy();
bool NPP_Print(NPPrint* platform_print);
void SendJavaScriptStream(const std::string& url, const std::wstring& result,
bool success, bool notify_needed, int notify_data);
void DidReceiveManualResponse(const std::string& url,
const std::string& mime_type,
const std::string& headers,
uint32 expected_length,
uint32 last_modified);
void DidReceiveManualData(const char* buffer, int length);
void DidFinishManualLoading();
void DidManualLoadFail();
NPError GetServiceManager(void** service_manager);
static BrowserPluginInstance* SetInitializingInstance(BrowserPluginInstance* instance);
static BrowserPluginInstance* GetInitializingInstance();
void PushPopupsEnabledState(bool enabled);
void PopPopupsEnabledState();
bool popups_allowed() const {
return popups_enabled_stack_.empty() ? false : popups_enabled_stack_.top();
}
// Initiates byte range reads for plugins.
void RequestRead(NPStream* stream, NPByteRange* range_list);
private:
void OnPluginThreadAsyncCall(void (*func)(void *),
void *userData);
bool IsValidStream(const NPStream* stream);
// This is a hack to get the real player plugin to work with chrome
// The real player plugin dll(nppl3260) when loaded by firefox is loaded via
// the NS COM API which is analogous to win32 COM. So the NPAPI functions in
// the plugin are invoked via an interface by firefox. The plugin instance
// handle which is passed to every NPAPI method is owned by the real player
// plugin, i.e. it expects the ndata member to point to a structure which
// it knows about. Eventually it dereferences this structure and compares
// a member variable at offset 0x24(Version 6.0.11.2888) /2D (Version
// 6.0.11.3088) with 0 and on failing this check, takes a different code
// path which causes a crash. Safari and Opera work with version 6.0.11.2888
// by chance as their ndata structure contains a 0 at the location which real
// player checks:(. They crash with version 6.0.11.3088 as well. The
// following member just adds a 96 byte padding to our BrowserPluginInstance class
// which is passed in the ndata member. This magic number works correctly on
// Vista with UAC on or off :(.
// NOTE: Please dont change the ordering of the member variables
// New members should be added after this padding array.
// TODO(iyengar) : Disassemble the Realplayer ndata structure and look into
// the possiblity of conforming to it (http://b/issue?id=936667). We
// could also log a bug with Real, which would save the effort.
uint8 zero_padding_[96];
scoped_refptr<NPAPI::BrowserPluginLib> plugin_;
NPP npp_;
scoped_refptr<PluginHost> host_;
NPPluginFuncs* npp_functions_;
std::vector<scoped_refptr<BrowserPluginStream> > open_streams_;
#if defined(OS_WIN)
HWND hwnd_;
#endif
bool windowless_;
bool transparent_;
WebPlugin* webplugin_;
std::string mime_type_;
GURL get_url_;
void* get_notify_data_;
bool use_mozilla_user_agent_;
#if defined(OS_WIN)
scoped_refptr<BrowserMozillaExtensionApi> mozilla_extenstions_;
#endif
MessageLoop* message_loop_;
// Using TLS to store BrowserPluginInstance object during its creation.
// We need to pass this instance to the service manager
// (MozillaExtensionApi) created as a result of NPN_GetValue
// in the context of NP_Initialize.
static ThreadLocalStorage::Slot plugin_instance_tls_index_;
scoped_refptr<BrowserPluginStreamUrl> plugin_data_stream_;
GURL instance_url_;
// This flag if true indicates that the plugin data would be passed from
// webkit. if false indicates that the plugin should download the data.
bool load_manually_;
// Stack indicating if popups are to be enabled for the outgoing
// NPN_GetURL/NPN_GetURLNotify calls.
std::stack<bool> popups_enabled_stack_;
// True if in CloseStreams().
bool in_close_streams_;
// List of files created for the current plugin instance. File names are
// added to the list every time the NPP_StreamAsFile function is called.
std::vector<FilePath> files_created_;
DISALLOW_EVIL_CONSTRUCTORS(BrowserPluginInstance);
};
} // namespace NPAPI
#endif // _BROWSER_PLUGIN_INSTANCE_H

View File

@ -0,0 +1,175 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "precompiled_libcef.h"
#include "config.h"
#include "browser_plugin_lib.h"
#include "browser_plugin_instance.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/plugins/plugin_host.h"
#include "net/base/mime_util.h"
namespace NPAPI
{
BrowserPluginLib::PluginMap* BrowserPluginLib::loaded_libs_;
BrowserPluginLib* BrowserPluginLib::GetOrCreatePluginLib(const struct CefPluginInfo& plugin_info) {
// We can only have one BrowserPluginLib object per plugin as it controls the
// per instance function calls (i.e. NP_Initialize and NP_Shutdown). So we
// keep a (non-ref counted) map of BrowserPluginLib objects.
if (!loaded_libs_)
loaded_libs_ = new PluginMap();
PluginMap::const_iterator iter =
loaded_libs_->find(plugin_info.version_info.unique_name);
if (iter != loaded_libs_->end())
return iter->second;
WebPluginInfo* info = CreateWebPluginInfo(plugin_info.version_info);
return new BrowserPluginLib(info, plugin_info);
}
BrowserPluginLib::BrowserPluginLib(WebPluginInfo* info,
const CefPluginInfo& plugin_info)
: web_plugin_info_(info),
plugin_info_(plugin_info),
initialized_(false),
saved_data_(0),
instance_count_(0) {
memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_));
(*loaded_libs_)[info->file] = this;
}
BrowserPluginLib::~BrowserPluginLib() {
if (saved_data_ != 0) {
// TODO - delete the savedData object here
}
}
NPPluginFuncs *BrowserPluginLib::functions() {
return &plugin_funcs_;
}
bool BrowserPluginLib::SupportsType(const std::string &mime_type,
bool allow_wildcard) {
// Webkit will ask for a plugin to handle empty mime types.
if (mime_type.empty())
return false;
for (size_t i = 0; i < web_plugin_info_->mime_types.size(); ++i) {
const WebPluginMimeType& mime_info = web_plugin_info_->mime_types[i];
if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
if (!allow_wildcard && (mime_info.mime_type == "*")) {
continue;
}
return true;
}
}
return false;
}
NPError BrowserPluginLib::NP_Initialize() {
if (initialized_)
return NPERR_NO_ERROR;
PluginHost *host = PluginHost::Singleton();
if (host == 0)
return NPERR_GENERIC_ERROR;
NPError rv = plugin_info_.np_initialize(host->host_functions());
initialized_ = (rv == NPERR_NO_ERROR);
if(initialized_) {
plugin_funcs_.size = sizeof(plugin_funcs_);
plugin_funcs_.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
if (plugin_info_.np_getentrypoints(&plugin_funcs_) != NPERR_NO_ERROR)
rv = false;
}
return rv;
}
void BrowserPluginLib::NP_Shutdown(void) {
DCHECK(initialized_);
plugin_info_.np_shutdown();
}
BrowserPluginInstance *BrowserPluginLib::CreateInstance(const std::string &mime_type) {
// The PluginInstance class uses the PluginLib member only for calling
// CloseInstance() from the PluginInstance destructor. We explicitly call
// CloseInstance() from BrowserWebPluginDelegateImpl::DestroyInstance().
BrowserPluginInstance *new_instance =
new BrowserPluginInstance(this, mime_type);
instance_count_++;
DCHECK(new_instance != 0);
return new_instance;
}
void BrowserPluginLib::CloseInstance() {
instance_count_--;
if (instance_count_ == 0) {
NP_Shutdown();
initialized_ = false;
loaded_libs_->erase(web_plugin_info_->file);
if (loaded_libs_->empty()) {
delete loaded_libs_;
loaded_libs_ = NULL;
}
}
}
WebPluginInfo* BrowserPluginLib::CreateWebPluginInfo(const CefPluginVersionInfo& plugin_info) {
std::vector<std::string> mime_types, file_extensions;
std::vector<std::wstring> descriptions;
SplitString(base::SysWideToNativeMB(plugin_info.mime_types), '|',
&mime_types);
SplitString(base::SysWideToNativeMB(plugin_info.file_extensions), '|',
&file_extensions);
SplitString(plugin_info.file_open_names, '|', &descriptions);
if (mime_types.empty())
return NULL;
WebPluginInfo *info = new WebPluginInfo();
info->name = plugin_info.product_name;
info->desc = plugin_info.description;
info->version = plugin_info.version;
info->file = StringToLowerASCII(plugin_info.unique_name);
for (size_t i = 0; i < mime_types.size(); ++i) {
WebPluginMimeType mime_type;
mime_type.mime_type = StringToLowerASCII(mime_types[i]);
if (file_extensions.size() > i)
SplitString(file_extensions[i], ',', &mime_type.file_extensions);
if (descriptions.size() > i) {
mime_type.description = descriptions[i];
// Remove the extension list from the description.
size_t ext = mime_type.description.find(L"(*");
if (ext != std::wstring::npos) {
if (ext > 1 && mime_type.description[ext -1] == ' ')
ext--;
mime_type.description.erase(ext);
}
}
info->mime_types.push_back(mime_type);
}
return info;
}
} // namespace NPAPI

View File

@ -0,0 +1,89 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _BROWSER_PLUGIN_LIB_H
#define _BROWSER_PLUGIN_LIB_H
#include <string>
#include "../../include/cef_nplugin.h"
#include "base/basictypes.h"
#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
struct WebPluginInfo;
namespace NPAPI
{
class BrowserPluginInstance;
// A BrowserPluginLib is a single NPAPI Plugin Library, and is the lifecycle
// manager for new PluginInstances.
class BrowserPluginLib : public base::RefCounted<BrowserPluginLib> {
public:
virtual ~BrowserPluginLib();
static BrowserPluginLib* GetOrCreatePluginLib(const struct CefPluginInfo& plugin_info);
// Get the Plugin's function pointer table.
NPPluginFuncs *functions();
// Returns true if this Plugin supports a given mime-type.
// mime_type should be all lower case.
bool SupportsType(const std::string &mime_type, bool allow_wildcard);
// Creates a new instance of this plugin.
BrowserPluginInstance *CreateInstance(const std::string &mime_type);
// Called by the instance when the instance is tearing down.
void CloseInstance();
// Gets information about this plugin and the mime types that it
// supports.
const WebPluginInfo& web_plugin_info() { return *web_plugin_info_; }
const struct CefPluginInfo& plugin_info() { return plugin_info_; }
//
// NPAPI functions
//
// NPAPI method to initialize a Plugin.
// Initialize can be safely called multiple times
NPError NP_Initialize();
// NPAPI method to shutdown a Plugin.
void NP_Shutdown(void);
int instance_count() const { return instance_count_; }
private:
// Creates a new BrowserPluginLib. The WebPluginInfo object is owned by this
// object. internal_plugin_info must not be NULL.
BrowserPluginLib(WebPluginInfo* info,
const CefPluginInfo& plugin_info);
// Creates WebPluginInfo structure based on read in or built in
// CefPluginVersionInfo.
static WebPluginInfo* CreateWebPluginInfo(const CefPluginVersionInfo& info);
scoped_ptr<WebPluginInfo> web_plugin_info_; // supported mime types, description
struct CefPluginInfo plugin_info_;
NPPluginFuncs plugin_funcs_; // the struct of plugin side functions
bool initialized_; // is the plugin initialized
NPSavedData *saved_data_; // persisted plugin info for NPAPI
int instance_count_; // count of plugins in use
// A map of all the insantiated plugins.
typedef base::hash_map<std::wstring, scoped_refptr<BrowserPluginLib> > PluginMap;
static PluginMap* loaded_libs_;
DISALLOW_EVIL_CONSTRUCTORS(BrowserPluginLib);
};
} // namespace NPAPI
#endif // _BROWSER_PLUGIN_LIB_H

View File

@ -0,0 +1,159 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "precompiled_libcef.h"
#include <algorithm>
#include <tchar.h>
#include "browser_plugin_list.h"
#include "browser_plugin_lib.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "googleurl/src/gurl.h"
namespace NPAPI
{
scoped_refptr<BrowserPluginList> BrowserPluginList::singleton_;
BrowserPluginList* BrowserPluginList::Singleton() {
if (singleton_.get() == NULL) {
singleton_ = new BrowserPluginList();
}
return singleton_;
}
BrowserPluginList::BrowserPluginList() {
}
BrowserPluginList::~BrowserPluginList() {
plugins_.clear();
}
void BrowserPluginList::AddPlugin(const struct CefPluginInfo& plugin_info) {
scoped_refptr<BrowserPluginLib> new_plugin
= BrowserPluginLib::GetOrCreatePluginLib(plugin_info);
if (!new_plugin.get())
return;
const WebPluginInfo& web_plugin_info = new_plugin->web_plugin_info();
for (size_t i = 0; i < web_plugin_info.mime_types.size(); ++i) {
const std::string &mime_type = web_plugin_info.mime_types[i].mime_type;
if (mime_type == "*")
continue;
if (!SupportsType(mime_type))
plugins_.push_back(new_plugin);
}
}
void BrowserPluginList::RemovePlugin(const struct CefPluginInfo& plugin_info)
{
PluginList::iterator it = plugins_.begin();
for(; it != plugins_.end(); ++it) {
if((*it)->web_plugin_info().file == plugin_info.version_info.unique_name) {
plugins_.erase(it);
}
}
}
BrowserPluginLib* BrowserPluginList::FindPlugin(const std::string& mime_type,
const std::string& clsid,
bool allow_wildcard) {
DCHECK(mime_type == StringToLowerASCII(mime_type));
for (size_t idx = 0; idx < plugins_.size(); ++idx) {
if (plugins_[idx]->SupportsType(mime_type, allow_wildcard)) {
return plugins_[idx];
}
}
return NULL;
}
BrowserPluginLib* BrowserPluginList::FindPlugin(const GURL &url,
std::string* actual_mime_type) {
std::wstring path = base::SysNativeMBToWide(url.path());
std::wstring extension_wide = file_util::GetFileExtensionFromPath(path);
if (extension_wide.empty())
return NULL;;
std::string extension =
StringToLowerASCII(base::SysWideToNativeMB(extension_wide));
for (size_t idx = 0; idx < plugins_.size(); ++idx) {
if (SupportsExtension(plugins_[idx]->web_plugin_info(), extension,
actual_mime_type)) {
return plugins_[idx];
}
}
return NULL;
}
bool BrowserPluginList::SupportsType(const std::string &mime_type) {
DCHECK(mime_type == StringToLowerASCII(mime_type));
bool allow_wildcard = true;
return (FindPlugin(mime_type, "", allow_wildcard ) != 0);
}
bool BrowserPluginList::SupportsExtension(const WebPluginInfo& info,
const std::string &extension,
std::string* actual_mime_type) {
for (size_t i = 0; i < info.mime_types.size(); ++i) {
const WebPluginMimeType& mime_type = info.mime_types[i];
for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) {
if (mime_type.file_extensions[j] == extension) {
if (actual_mime_type)
*actual_mime_type = mime_type.mime_type;
return true;
}
}
}
return false;
}
bool BrowserPluginList::GetPlugins(bool refresh,
std::vector<WebPluginInfo>* plugins) {
plugins->resize(plugins_.size());
for (size_t i = 0; i < plugins->size(); ++i)
(*plugins)[i] = plugins_[i]->web_plugin_info();
return true;
}
bool BrowserPluginList::GetPluginInfo(const GURL& url,
const std::string& mime_type,
const std::string& clsid,
bool allow_wildcard,
struct CefPluginInfo* plugin_info,
std::string* actual_mime_type) {
scoped_refptr<BrowserPluginLib> plugin = FindPlugin(mime_type, clsid,
allow_wildcard);
if (plugin.get() == NULL)
plugin = FindPlugin(url, actual_mime_type);
if (plugin.get() == NULL)
return false;
*plugin_info = plugin->plugin_info();
return true;
}
void BrowserPluginList::Shutdown() {
// TODO
}
} // namespace NPAPI

View File

@ -0,0 +1,99 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO: Need mechanism to cleanup the static instance
#ifndef _BROWSER_PLUGIN_LIST_H
#define _BROWSER_PLUGIN_LIST_H
#include <string>
#include <vector>
#include "../../include/cef_nplugin.h"
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "webkit/glue/webplugin.h"
class GURL;
namespace NPAPI
{
class BrowserPluginLib;
class PluginInstance;
// The BrowserPluginList is responsible for loading internal NPAPI based
// plugins. Call the LoadPlugin() method to load an internal plugin.
class BrowserPluginList : public base::RefCounted<BrowserPluginList> {
public:
// Gets the one instance of the BrowserPluginList.
static BrowserPluginList* Singleton();
virtual ~BrowserPluginList();
// Add a plugin using the specified info structure.
void AddPlugin(const struct CefPluginInfo& plugin_info);
// Remove the plugin matching the specified info structure.
void RemovePlugin(const struct CefPluginInfo& plugin_info);
// Find a plugin by mime type and clsid.
// If clsid is empty, we will just find the plugin that supports mime type.
// The allow_wildcard parameter controls whether this function returns
// plugins which support wildcard mime types (* as the mime type)
BrowserPluginLib* FindPlugin(const std::string &mime_type,
const std::string& clsid, bool allow_wildcard);
// Find a plugin to by extension. Returns the corresponding mime type.
BrowserPluginLib* FindPlugin(const GURL &url, std::string* actual_mime_type);
// Check if we have any plugin for a given type.
// mime_type must be all lowercase.
bool SupportsType(const std::string &mime_type);
// Returns true if the given WebPluginInfo supports a given file extension.
// extension should be all lower case.
// If mime_type is not NULL, it will be set to the mime type if found.
// The mime type which corresponds to the extension is optionally returned
// back.
static bool SupportsExtension(const WebPluginInfo& info,
const std::string &extension,
std::string* actual_mime_type);
// Shutdown all plugins. Should be called at process teardown.
void Shutdown();
// Get all the plugins
bool GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins);
// Returns true if a plugin is found for the given url and mime type.
// The mime type which corresponds to the URL is optionally returned
// back.
// The allow_wildcard parameter controls whether this function returns
// plugins which support wildcard mime types (* as the mime type)
bool GetPluginInfo(const GURL& url,
const std::string& mime_type,
const std::string& clsid,
bool allow_wildcard,
struct CefPluginInfo* plugin_info,
std::string* actual_mime_type);
private:
// Constructors are private for singletons
BrowserPluginList();
static scoped_refptr<BrowserPluginList> singleton_;
typedef std::vector<scoped_refptr<BrowserPluginLib> > PluginList;
PluginList plugins_;
DISALLOW_EVIL_CONSTRUCTORS(BrowserPluginList);
};
} // namespace NPAPI
#endif // _BROWSER_PLUGIN_LIST_H

View File

@ -0,0 +1,247 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO : Support NP_ASFILEONLY mode
// TODO : Support NP_SEEK mode
// TODO : Support SEEKABLE=true in NewStream
#include "precompiled_libcef.h"
#include "browser_plugin_stream.h"
#include "browser_plugin_instance.h"
#include "base/string_util.h"
#include "base/message_loop.h"
#include "webkit/glue/webkit_glue.h"
#include "googleurl/src/gurl.h"
namespace NPAPI {
BrowserPluginStream::~BrowserPluginStream() {
// always close our temporary files.
CloseTempFile();
free(const_cast<char*>(stream_.url));
}
bool BrowserPluginStream::Open(const std::string &mime_type,
const std::string &headers,
uint32 length,
uint32 last_modified) {
headers_ = headers;
NPP id = instance_->npp();
stream_.end = length;
stream_.lastmodified = last_modified;
stream_.pdata = 0;
stream_.ndata = id->ndata;
stream_.notifyData = notify_data_;
bool seekable_stream = false;
if (!headers_.empty()) {
stream_.headers = headers_.c_str();
if (headers_.find("Accept-Ranges: bytes") != std::string::npos) {
seekable_stream = true;
}
}
const char *char_mime_type = "application/x-unknown-content-type";
std::string temp_mime_type;
if (!mime_type.empty()) {
char_mime_type = mime_type.c_str();
} else {
GURL gurl(stream_.url);
std::wstring path(UTF8ToWide(gurl.path()));
if (webkit_glue::GetMimeTypeFromFile(path, &temp_mime_type))
char_mime_type = temp_mime_type.c_str();
}
// Silverlight expects a valid mime type
DCHECK(strlen(char_mime_type) != 0);
NPError err = instance_->NPP_NewStream((NPMIMEType)char_mime_type,
&stream_, seekable_stream,
&requested_plugin_mode_);
if (err != NPERR_NO_ERROR) {
Notify(err);
return false;
}
opened_ = true;
if (requested_plugin_mode_ == NP_SEEK) {
seekable_stream_ = true;
}
// If the plugin has requested certain modes, then we need a copy
// of this file on disk. Open it and save it as we go.
if (requested_plugin_mode_ == NP_ASFILEONLY ||
requested_plugin_mode_ == NP_ASFILE) {
if (OpenTempFile() == false)
return false;
}
mime_type_ = char_mime_type;
return true;
}
int BrowserPluginStream::Write(const char *buffer, const int length,
int data_offset) {
// There may be two streams to write to - the plugin and the file.
// It is unclear what to do if we cannot write to both. The rules of
// this function are that the plugin must consume at least as many
// bytes as returned by the WriteReady call. So, we will attempt to
// write that many to both streams. If we can't write that many bytes
// to each stream, we'll return failure.
DCHECK(opened_);
if (WriteToFile(buffer, length) &&
WriteToPlugin(buffer, length, data_offset))
return length;
return -1;
}
bool BrowserPluginStream::WriteToFile(const char *buf, size_t length) {
// For ASFILEONLY, ASFILE, and SEEK modes, we need to write
// to the disk
if (TempFileIsValid() &&
(requested_plugin_mode_ == NP_ASFILE ||
requested_plugin_mode_ == NP_ASFILEONLY) ) {
size_t totalBytesWritten = 0, bytes;
do {
bytes = WriteBytes(buf, length);
totalBytesWritten += bytes;
} while (bytes > 0U && totalBytesWritten < length);
if (totalBytesWritten != length)
return false;
}
return true;
}
bool BrowserPluginStream::WriteToPlugin(const char *buf, const int length,
const int data_offset) {
// For NORMAL and ASFILE modes, we send the data to the plugin now
if (requested_plugin_mode_ != NP_NORMAL &&
requested_plugin_mode_ != NP_ASFILE &&
requested_plugin_mode_ != NP_SEEK)
return true;
int written = TryWriteToPlugin(buf, length, data_offset);
if (written == -1)
return false;
if (written < length) {
// Buffer the remaining data.
size_t remaining = length - written;
size_t previous_size = delivery_data_.size();
delivery_data_.resize(previous_size + remaining);
data_offset_ = data_offset;
memcpy(&delivery_data_[previous_size], buf + written, remaining);
MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
this, &BrowserPluginStream::OnDelayDelivery));
}
return true;
}
void BrowserPluginStream::OnDelayDelivery() {
// It is possible that the plugin stream may have closed before the task
// was hit.
if (!opened_) {
return;
}
int size = static_cast<int>(delivery_data_.size());
int written = TryWriteToPlugin(&delivery_data_.front(), size,
data_offset_);
if (written > 0) {
// Remove the data that we already wrote.
delivery_data_.erase(delivery_data_.begin(),
delivery_data_.begin() + written);
}
}
int BrowserPluginStream::TryWriteToPlugin(const char *buf, const int length,
const int data_offset) {
int byte_offset = 0;
if (data_offset > 0)
data_offset_ = data_offset;
while (byte_offset < length) {
int bytes_remaining = length - byte_offset;
int bytes_to_write = instance_->NPP_WriteReady(&stream_);
if (bytes_to_write > bytes_remaining)
bytes_to_write = bytes_remaining;
if (bytes_to_write == 0)
return byte_offset;
int bytes_consumed = instance_->NPP_Write(
&stream_, data_offset_, bytes_to_write,
const_cast<char*>(buf + byte_offset));
if (bytes_consumed < 0) {
// The plugin failed, which means that we need to close the stream.
Close(NPRES_NETWORK_ERR);
return -1;
}
if (bytes_consumed == 0) {
// The plugin couldn't take all of the data now.
return byte_offset;
}
// The plugin might report more that we gave it.
bytes_consumed = std::min(bytes_consumed, bytes_to_write);
data_offset_ += bytes_consumed;
byte_offset += bytes_consumed;
}
if (close_on_write_data_)
Close(NPRES_DONE);
return length;
}
bool BrowserPluginStream::Close(NPReason reason) {
if (opened_ == true) {
opened_ = false;
if (delivery_data_.size()) {
if (reason == NPRES_DONE) {
// There is more data to be streamed, don't destroy the stream now.
close_on_write_data_ = true;
return true;
} else {
// Stop any pending data from being streamed
delivery_data_.resize(0);
}
}
// If we have a temp file, be sure to close it.
// Also, allow the plugin to access it now.
if (TempFileIsValid()) {
CloseTempFile();
WriteAsFile();
}
if (stream_.ndata != NULL) {
// Stream hasn't been closed yet.
NPError err = instance_->NPP_DestroyStream(&stream_, reason);
DCHECK(err == NPERR_NO_ERROR);
}
}
Notify(reason);
return true;
}
void BrowserPluginStream::Notify(NPReason reason) {
if (notify_needed_) {
instance_->NPP_URLNotify(stream_.url, reason, notify_data_);
notify_needed_ = false;
}
}
} // namespace NPAPI

View File

@ -0,0 +1,137 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _BROWSER_PLUGIN_STREAM_H
#define _BROWSER_PLUGIN_STREAM_H
#include <string>
#include <vector>
#include "base/file_path.h"
#include "base/ref_counted.h"
#include "third_party/npapi/bindings/npapi.h"
class WebPluginResourceClient;
namespace NPAPI {
class BrowserPluginInstance;
// Base class for a NPAPI stream. Tracks basic elements
// of a stream for NPAPI notifications and stream position.
class BrowserPluginStream : public base::RefCounted<BrowserPluginStream> {
public:
// Create a new BrowserPluginStream object. If needNotify is true, then the
// plugin will be notified when the stream has been fully sent.
BrowserPluginStream(BrowserPluginInstance *instance,
const char *url,
bool need_notify,
void *notify_data);
virtual ~BrowserPluginStream();
// In case of a redirect, this can be called to update the url. But it must
// be called before Open().
void UpdateUrl(const char* url);
// Opens the stream to the Plugin.
// If the mime-type is not specified, we'll try to find one based on the
// mime-types table and the extension (if any) in the URL.
// If the size of the stream is known, use length to set the size. If
// not known, set length to 0.
bool Open(const std::string &mime_type,
const std::string &headers,
uint32 length,
uint32 last_modified);
// Writes to the stream.
int Write(const char *buf, const int len, int data_offset);
// Write the result as a file.
void WriteAsFile();
// Notify the plugin that a stream is complete.
void Notify(NPReason reason);
// Close the stream.
virtual bool Close(NPReason reason);
virtual WebPluginResourceClient* AsResourceClient() { return NULL; }
// Cancels any HTTP requests initiated by the stream.
virtual void CancelRequest() {}
const NPStream* stream() const { return &stream_; }
// setter/getter for the seekable attribute on the stream.
bool seekable() const { return seekable_stream_; }
void set_seekable(bool seekable) { seekable_stream_ = seekable; }
// getters for reading the notification related attributes on the stream.
bool notify_needed() const { return notify_needed_; }
void* notify_data() const { return notify_data_; }
protected:
BrowserPluginInstance* instance() { return instance_.get(); }
// Check if the stream is open.
bool open() { return opened_; }
private:
// Open a temporary file for this stream.
// If successful, will set temp_file_name_, temp_file_handle_, and
// return true.
bool OpenTempFile();
// Closes the temporary file if it is open.
void CloseTempFile();
// Sends the data to the file. Called From WriteToFile.
size_t WriteBytes(const char *buf, size_t length);
// Sends the data to the file if it's open.
bool WriteToFile(const char *buf, size_t length);
// Sends the data to the plugin. If it's not ready, handles buffering it
// and retrying later.
bool WriteToPlugin(const char *buf, const int length, const int data_offset);
// Send the data to the plugin, returning how many bytes it accepted, or -1
// if an error occurred.
int TryWriteToPlugin(const char *buf, const int length, const int data_offset);
// The callback which calls TryWriteToPlugin.
void OnDelayDelivery();
// Returns true if the temp file is valid and open for writing.
bool TempFileIsValid();
private:
NPStream stream_;
std::string headers_;
scoped_refptr<BrowserPluginInstance> instance_;
bool notify_needed_;
void * notify_data_;
bool close_on_write_data_;
uint16 requested_plugin_mode_;
bool opened_;
#if defined(OS_WIN)
char temp_file_name_[MAX_PATH];
HANDLE temp_file_handle_;
#elif defined(OS_POSIX)
FILE* temp_file_;
FilePath temp_file_path_;
#endif
std::vector<char> delivery_data_;
int data_offset_;
bool seekable_stream_;
std::string mime_type_;
DISALLOW_EVIL_CONSTRUCTORS(BrowserPluginStream);
};
} // namespace NPAPI
#endif // _BROWSER_PLUGIN_STREAM_H

View File

@ -0,0 +1,86 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "precompiled_libcef.h"
#include "browser_plugin_stream_url.h"
#include "browser_plugin_instance.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webplugin.h"
#include "webkit/glue/plugins/plugin_host.h"
namespace NPAPI {
BrowserPluginStreamUrl::BrowserPluginStreamUrl(
int resource_id,
const GURL &url,
BrowserPluginInstance *instance,
bool notify_needed,
void *notify_data)
: BrowserPluginStream(instance, url.spec().c_str(), notify_needed, notify_data),
url_(url),
id_(resource_id) {
}
BrowserPluginStreamUrl::~BrowserPluginStreamUrl() {
}
bool BrowserPluginStreamUrl::Close(NPReason reason) {
CancelRequest();
bool result = BrowserPluginStream::Close(reason);
instance()->RemoveStream(this);
return result;
}
void BrowserPluginStreamUrl::WillSendRequest(const GURL& url) {
url_ = url;
UpdateUrl(url.spec().c_str());
}
void BrowserPluginStreamUrl::DidReceiveResponse(const std::string& mime_type,
const std::string& headers,
uint32 expected_length,
uint32 last_modified,
bool* cancel) {
bool opened = Open(mime_type,
headers,
expected_length,
last_modified);
if (!opened) {
instance()->RemoveStream(this);
*cancel = true;
}
}
void BrowserPluginStreamUrl::DidReceiveData(const char* buffer, int length,
int data_offset) {
if (!open())
return;
if (length > 0)
Write(const_cast<char*>(buffer), length, data_offset);
}
void BrowserPluginStreamUrl::DidFinishLoading() {
if (!seekable()) {
Close(NPRES_DONE);
}
}
void BrowserPluginStreamUrl::DidFail() {
Close(NPRES_NETWORK_ERR);
}
void BrowserPluginStreamUrl::CancelRequest() {
if (id_ > 0) {
if (instance()->webplugin()) {
instance()->webplugin()->CancelResource(id_);
}
id_ = 0;
}
}
} // namespace NPAPI

View File

@ -0,0 +1,67 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _BROWSER_PLUGIN_STREAM_URL_H
#define _BROWSER_PLUGIN_STREAM_URL_H
#include "browser_plugin_stream.h"
#include "webkit/glue/webplugin.h"
#include "googleurl/src/gurl.h"
namespace NPAPI {
class BrowserPluginInstance;
// A NPAPI Stream based on a URL.
class BrowserPluginStreamUrl : public BrowserPluginStream,
public WebPluginResourceClient {
public:
// Create a new stream for sending to the plugin by fetching
// a URL. If notifyNeeded is set, then the plugin will be notified
// when the stream has been fully sent to the plugin. Initialize
// must be called before the object is used.
BrowserPluginStreamUrl(int resource_id,
const GURL &url,
BrowserPluginInstance *instance,
bool notify_needed,
void *notify_data);
virtual ~BrowserPluginStreamUrl();
// Stop sending the stream to the client.
// Overrides the base Close so we can cancel our fetching the URL if
// it is still loading.
virtual bool Close(NPReason reason);
virtual WebPluginResourceClient* AsResourceClient() {
return static_cast<WebPluginResourceClient*>(this);
}
virtual void CancelRequest();
//
// WebPluginResourceClient methods
//
void WillSendRequest(const GURL& url);
void DidReceiveResponse(const std::string& mime_type,
const std::string& headers,
uint32 expected_length,
uint32 last_modified,
bool* cancel);
void DidReceiveData(const char* buffer, int length, int data_offset);
void DidFinishLoading();
void DidFail();
private:
GURL url_;
int id_;
DISALLOW_EVIL_CONSTRUCTORS(BrowserPluginStreamUrl);
};
} // namespace NPAPI
#endif // _BROWSER_PLUGIN_STREAM_URL_H

View File

@ -0,0 +1,99 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "precompiled_libcef.h"
#include "browser_plugin_stream.h"
#include "browser_plugin_instance.h"
#include "base/logging.h"
namespace NPAPI {
BrowserPluginStream::BrowserPluginStream(
BrowserPluginInstance *instance,
const char *url,
bool need_notify,
void *notify_data)
: instance_(instance),
notify_needed_(need_notify),
notify_data_(notify_data),
close_on_write_data_(false),
opened_(false),
requested_plugin_mode_(NP_NORMAL),
temp_file_handle_(INVALID_HANDLE_VALUE),
seekable_stream_(false),
data_offset_(0) {
memset(&stream_, 0, sizeof(stream_));
stream_.url = _strdup(url);
temp_file_name_[0] = '\0';
}
void BrowserPluginStream::UpdateUrl(const char* url) {
DCHECK(!opened_);
free(const_cast<char*>(stream_.url));
stream_.url = _strdup(url);
}
void BrowserPluginStream::WriteAsFile() {
if (requested_plugin_mode_ == NP_ASFILE ||
requested_plugin_mode_ == NP_ASFILEONLY)
instance_->NPP_StreamAsFile(&stream_, temp_file_name_);
}
size_t BrowserPluginStream::WriteBytes(const char *buf, size_t length) {
DWORD bytes;
if (!WriteFile(temp_file_handle_, buf, length, &bytes, 0))
return 0U;
return static_cast<size_t>(bytes);
}
bool BrowserPluginStream::OpenTempFile() {
DCHECK(temp_file_handle_ == INVALID_HANDLE_VALUE);
// The reason for using all the Ascii versions of these filesystem
// calls is that the filename which we pass back to the plugin
// via NPAPI is an ascii filename. Otherwise, we'd use wide-chars.
//
// TODO:
// This is a bug in NPAPI itself, and it needs to be fixed.
// The case which will fail is if a user has a multibyte name,
// but has the system locale set to english. GetTempPathA will
// return junk in this case, causing us to be unable to open the
// file.
char temp_directory[MAX_PATH];
if (GetTempPathA(MAX_PATH, temp_directory) == 0)
return false;
if (GetTempFileNameA(temp_directory, "npstream", 0, temp_file_name_) == 0)
return false;
temp_file_handle_ = CreateFileA(temp_file_name_,
FILE_ALL_ACCESS,
FILE_SHARE_READ,
0,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
if (temp_file_handle_ == INVALID_HANDLE_VALUE) {
temp_file_name_[0] = '\0';
return false;
}
return true;
}
void BrowserPluginStream::CloseTempFile() {
if (temp_file_handle_ != INVALID_HANDLE_VALUE) {
CloseHandle(temp_file_handle_);
temp_file_handle_ = INVALID_HANDLE_VALUE;
}
}
bool BrowserPluginStream::TempFileIsValid() {
return temp_file_handle_ != INVALID_HANDLE_VALUE;
}
} // namespace NPAPI

View File

@ -0,0 +1,34 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "precompiled_libcef.h"
#include "browser_plugin_string_stream.h"
namespace NPAPI {
BrowserPluginStringStream::BrowserPluginStringStream(
BrowserPluginInstance *instance,
const std::string &url,
bool notify_needed,
void *notify_data)
: BrowserPluginStream(instance, url.c_str(), notify_needed, notify_data) {
}
BrowserPluginStringStream::~BrowserPluginStringStream() {
}
void BrowserPluginStringStream::SendToPlugin(const std::string &data,
const std::string &mime_type) {
int length = static_cast<int>(data.length());
if (Open(mime_type, std::string(), length, 0)) {
// TODO - check if it was not fully sent, and figure out a backup plan.
int written = Write(data.c_str(), length, 0);
NPReason reason = written == length ? NPRES_DONE : NPRES_NETWORK_ERR;
Close(reason);
}
}
}

View File

@ -0,0 +1,39 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _BROWSER_PLUGIN_STRING_STREAM_H
#define _BROWSER_PLUGIN_STRING_STREAM_H
#include "browser_plugin_stream.h"
namespace NPAPI {
class BrowserPluginInstance;
// An NPAPI stream from a string.
class BrowserPluginStringStream : public BrowserPluginStream {
public:
// Create a new stream for sending to the plugin.
// If notify_needed, will notify the plugin after the data has
// all been sent.
BrowserPluginStringStream(BrowserPluginInstance *instance,
const std::string &url,
bool notify_needed,
void *notify_data);
virtual ~BrowserPluginStringStream();
// Initiates the sending of data to the plugin.
void SendToPlugin(const std::string &data,
const std::string &mime_type);
private:
DISALLOW_EVIL_CONSTRUCTORS(BrowserPluginStringStream);
};
} // namespace NPAPI
#endif // _BROWSER_PLUGIN_STRING_STREAM_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,283 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _BROWSER_WEBPLUGIN_DELEGATE_IMPL_H
#define _BROWSER_WEBPLUGIN_DELEGATE_IMPL_H
#include <string>
#include <list>
#include "browser_plugin_lib.h"
#include "base/iat_patch.h"
#include "base/ref_counted.h"
#include "base/task.h"
#include "webkit/glue/webplugin_delegate.h"
#include "third_party/npapi/bindings/npapi.h"
#include "webkit/glue/webcursor.h"
namespace NPAPI {
class BrowserPluginInstance;
};
// An implementation of WebPluginDelegate that proxies all calls to
// the plugin process.
class BrowserWebPluginDelegateImpl : public WebPluginDelegate {
public:
static BrowserWebPluginDelegateImpl* Create(const struct CefPluginInfo& plugin_info,
const std::string& mime_type,
HWND containing_window);
static bool IsPluginDelegateWindow(HWND window);
static bool GetPluginNameFromWindow(HWND window, std::wstring *plugin_name);
// Returns true if the window handle passed in is that of the dummy
// activation window for windowless plugins.
static bool IsDummyActivationWindow(HWND window);
// WebPluginDelegate implementation
virtual void PluginDestroyed();
virtual bool Initialize(const GURL& url,
char** argn,
char** argv,
int argc,
WebPlugin* plugin,
bool load_manually);
virtual void UpdateGeometry(const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
const std::vector<gfx::Rect>& cutout_rects,
bool visible);
virtual void Paint(HDC hdc, const gfx::Rect& rect);
virtual void Print(HDC hdc);
virtual void SetFocus(); // only called when windowless
// only called when windowless
virtual bool HandleEvent(NPEvent* event,
WebCursor* cursor);
virtual NPObject* GetPluginScriptableObject();
virtual void DidFinishLoadWithReason(NPReason reason);
virtual int GetProcessId();
virtual void FlushGeometryUpdates() {
}
virtual void SendJavaScriptStream(const std::string& url,
const std::wstring& result,
bool success, bool notify_needed,
int notify_data);
virtual void DidReceiveManualResponse(const std::string& url,
const std::string& mime_type,
const std::string& headers,
uint32 expected_length,
uint32 last_modified);
virtual void DidReceiveManualData(const char* buffer, int length);
virtual void DidFinishManualLoading();
virtual void DidManualLoadFail();
virtual std::wstring GetPluginPath();
virtual void InstallMissingPlugin();
virtual WebPluginResourceClient* CreateResourceClient(int resource_id,
const std::string &url,
bool notify_needed,
void *notify_data,
void* stream);
virtual void URLRequestRouted(const std::string&url, bool notify_needed,
void* notify_data);
bool windowless() const { return windowless_ ; }
gfx::Rect rect() const { return window_rect_; }
gfx::Rect clip_rect() const { return clip_rect_; }
enum PluginQuirks {
PLUGIN_QUIRK_SETWINDOW_TWICE = 1,
PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE = 2,
PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY = 4,
PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY = 8,
PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES = 16,
PLUGIN_QUIRK_DIE_AFTER_UNLOAD = 32,
PLUGIN_QUIRK_PATCH_TRACKPOPUP_MENU = 64,
};
int quirks() { return quirks_; }
static void MoveWindow(HWND window,
const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
const std::vector<gfx::Rect>& cutout_rects,
bool visible);
private:
BrowserWebPluginDelegateImpl(HWND containing_window,
NPAPI::BrowserPluginInstance *instance);
~BrowserWebPluginDelegateImpl();
//--------------------------
// used for windowed plugins
void WindowedUpdateGeometry(const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
const std::vector<gfx::Rect>& cutout_rects,
bool visible);
// Create the native window.
// Returns true if the window is created (or already exists).
// Returns false if unable to create the window.
bool WindowedCreatePlugin();
// Destroy the native window.
void WindowedDestroyWindow();
// Reposition the native window to be in sync with the given geometry.
// Returns true if the native window has moved or been clipped differently.
bool WindowedReposition(const gfx::Rect& window_rect,
const gfx::Rect& clip_rect,
const std::vector<gfx::Rect>& cutout_rects,
bool visible);
// Tells the plugin about the current state of the window.
// See NPAPI NPP_SetWindow for more information.
void WindowedSetWindow();
// Registers the window class for our window
ATOM RegisterNativeWindowClass();
// Our WndProc functions.
static LRESULT CALLBACK DummyWindowProc(
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK NativeWndProc(
HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
static LRESULT CALLBACK FlashWindowlessWndProc(
HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
// Used for throttling Flash messages.
static void ClearThrottleQueueForWindow(HWND window);
static void OnThrottleMessage();
static void ThrottleMessage(WNDPROC proc, HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam);
//----------------------------
// used for windowless plugins
void WindowlessUpdateGeometry(const gfx::Rect& window_rect,
const gfx::Rect& clip_rect);
void WindowlessPaint(HDC hdc, const gfx::Rect& rect);
// Tells the plugin about the current state of the window.
// See NPAPI NPP_SetWindow for more information.
void WindowlessSetWindow(bool force_set_window);
//-----------------------------------------
// used for windowed and windowless plugins
NPAPI::BrowserPluginInstance* instance() { return instance_.get(); }
// Closes down and destroys our plugin instance.
void DestroyInstance();
// used for windowed plugins
HWND windowed_handle_;
bool windowed_did_set_window_;
gfx::Rect windowed_last_pos_;
// this is an optimization to avoid calling SetWindow to the plugin
// when it is not necessary. Initially, we need to call SetWindow,
// and after that we only need to call it when the geometry changes.
// use this flag to indicate whether we really need it or not.
bool windowless_needs_set_window_;
// used by windowed and windowless plugins
bool windowless_;
WebPlugin* plugin_;
scoped_refptr<NPAPI::BrowserPluginInstance> instance_;
// Original wndproc before we subclassed.
WNDPROC plugin_wnd_proc_;
// Used to throttle WM_USER+1 messages in Flash.
uint32 last_message_;
bool is_calling_wndproc;
HWND parent_;
NPWindow window_;
gfx::Rect window_rect_;
gfx::Rect clip_rect_;
std::vector<gfx::Rect> cutout_rects_;
int quirks_;
// We only move/size the plugin window once after its creation. The
// rest of the moves are controlled by the browser. This flag controls
// this behaviour.
bool initial_plugin_resize_done_;
// Windowless plugins don't have keyboard focus causing issues with the
// plugin not receiving keyboard events if the plugin enters a modal
// loop like TrackPopupMenuEx or MessageBox, etc.
// This is a basic issue with windows activation and focus arising due to
// the fact that these windows are created by different threads. Activation
// and focus are thread specific states, and if the browser has focus,
// the plugin may not have focus.
// To fix a majority of these activation issues we create a dummy visible
// child window to which we set focus whenever the windowless plugin
// receives a WM_LBUTTONDOWN/WM_RBUTTONDOWN message via NPP_HandleEvent.
HWND dummy_window_for_activation_;
bool CreateDummyWindowForActivation();
static std::list<MSG> throttle_queue_;
// Returns true if the event passed in needs to be tracked for a potential
// modal loop.
static bool ShouldTrackEventForModalLoops(NPEvent* event);
// The message filter hook procedure, which tracks modal loops entered by
// a plugin in the course of a NPP_HandleEvent call.
static LRESULT CALLBACK HandleEventMessageFilterHook(int code, WPARAM wParam,
LPARAM lParam);
// Called by the message filter hook when the plugin enters a modal loop.
void OnModalLoopEntered();
// Returns true if the message passed in corresponds to a user gesture.
static bool IsUserGestureMessage(unsigned int message);
// Indicates the end of a user gesture period.
void OnUserGestureEnd();
// Handle to the message filter hook
HHOOK handle_event_message_filter_hook_;
// The current instance of the plugin which entered the modal loop.
static BrowserWebPluginDelegateImpl* current_plugin_instance_;
// Event which is set when the plugin enters a modal loop in the course
// of a NPP_HandleEvent call.
HANDLE handle_event_pump_messages_event_;
// Holds the depth of the HandleEvent callstack.
int handle_event_depth_;
// This flag indicates whether we started tracking a user gesture message.
bool user_gesture_message_posted_;
// Runnable Method Factory used to invoke the OnUserGestureEnd method
// asynchronously.
ScopedRunnableMethodFactory<BrowserWebPluginDelegateImpl> user_gesture_msg_factory_;
// The url with which the plugin was instantiated.
std::string plugin_url_;
// The plugin module handle.
HMODULE plugin_module_handle_;
// Indicates whether we IAT patched the TrackPopupMenu function.
static bool track_popup_menu_patched_;
// Helper object for patching the import table of Silverlight.
static iat_patch::IATPatchFunction iat_patch_helper_;
// TrackPopupMenu interceptor. Parameters are the same as the Win32 function
// TrackPopupMenu.
static BOOL WINAPI TrackPopupMenuPatch(HMENU menu, unsigned int flags, int x,
int y, int reserved, HWND window,
const RECT* rect);
DISALLOW_EVIL_CONSTRUCTORS(BrowserWebPluginDelegateImpl);
};
#endif // #ifndef _BROWSER_WEBPLUGIN_DELEGATE_IMPL_H

View File

@ -5,6 +5,7 @@
#include "stdafx.h"
#include "cefclient.h"
#include "clientplugin.h"
#include "cef.h"
#include <sstream>
@ -36,6 +37,9 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
// Initialize the CEF
CefInitialize();
// Register the internal client plugin
CefRegisterPlugin(ClientPluginInfo);
MSG msg;
HACCEL hAccelTable;
@ -716,7 +720,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
L"http://www.google.com");
// Start the timer that will be used to update child window state
SetTimer(hWnd, 1, 500, NULL);
SetTimer(hWnd, 1, 250, NULL);
}
return 0;
@ -781,6 +785,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
browser->LoadString(html, L"about:blank");
}
return 0;
case ID_TESTS_PLUGIN: // Test our custom plugin
if(browser.get())
{
std::wstring html =
L"<html><body>Client Plugin:<br>"
L"<embed type=\"application/x-client-plugin\""
L"width=600 height=40>"
L"</body></html>";
browser->LoadString(html, L"about:blank");
}
}
}
break;

View File

@ -58,6 +58,7 @@ BEGIN
POPUP "Tests"
BEGIN
MENUITEM "JavaScript", ID_TESTS_JAVASCRIPT
MENUITEM "Plugin", ID_TESTS_PLUGIN
END
END

View File

@ -181,6 +181,14 @@
RelativePath=".\cefclient.rc"
>
</File>
<File
RelativePath=".\clientplugin.cpp"
>
</File>
<File
RelativePath=".\clientplugin.h"
>
</File>
<File
RelativePath=".\Resource.h"
>

View File

@ -0,0 +1,185 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "stdafx.h"
#include "clientplugin.h"
// Initialized in NP_Initialize.
NPNetscapeFuncs* g_browser = NULL;
NPError NPP_New(NPMIMEType plugin_type, NPP instance, uint16 mode, int16 argc,
char* argn[], char* argv[], NPSavedData* saved) {
if (instance == NULL)
return NPERR_INVALID_INSTANCE_ERROR;
ClientPlugin* plugin_impl = new ClientPlugin(mode);
plugin_impl->Initialize(GetModuleHandle(NULL), instance, plugin_type, argc,
argn, argv);
instance->pdata = reinterpret_cast<void*>(plugin_impl);
return NPERR_NO_ERROR;
}
NPError NPP_Destroy(NPP instance, NPSavedData** save) {
ClientPlugin* plugin_impl = reinterpret_cast<ClientPlugin*>(instance->pdata);
if (plugin_impl) {
plugin_impl->Shutdown();
delete plugin_impl;
}
return NPERR_NO_ERROR;
}
NPError NPP_SetWindow(NPP instance, NPWindow* window_info) {
if (instance == NULL)
return NPERR_INVALID_INSTANCE_ERROR;
if (window_info == NULL)
return NPERR_GENERIC_ERROR;
ClientPlugin* plugin_impl = reinterpret_cast<ClientPlugin*>(instance->pdata);
if (plugin_impl == NULL)
return NPERR_GENERIC_ERROR;
HWND window_handle = reinterpret_cast<HWND>(window_info->window);
if (!plugin_impl->SetWindow(window_handle)) {
delete plugin_impl;
return NPERR_GENERIC_ERROR;
}
return NPERR_NO_ERROR;
}
NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* pFuncs)
{
pFuncs->newp = NPP_New;
pFuncs->destroy = NPP_Destroy;
pFuncs->setwindow = NPP_SetWindow;
return NPERR_NO_ERROR;
}
NPError API_CALL NP_Initialize(NPNetscapeFuncs* pFuncs)
{
g_browser = pFuncs;
return NPERR_NO_ERROR;
}
NPError API_CALL NP_Shutdown(void)
{
g_browser = NULL;
return NPERR_NO_ERROR;
}
// ClientPlugin Implementation
ClientPlugin::ClientPlugin(int16 mode)
: mode_(mode)
{
}
ClientPlugin::~ClientPlugin()
{
}
bool ClientPlugin::Initialize(HINSTANCE module_handle, NPP instance,
NPMIMEType mime_type, int16 argc, char* argn[],
char* argv[])
{
RefreshDisplay();
return true;
}
bool ClientPlugin::SetWindow(HWND parent_window)
{
if (!::IsWindow(parent_window)) {
// No window created yet. Ignore this call.
if (!IsWindow())
return true;
// Parent window has been destroyed.
Shutdown();
return true;
}
RECT parent_rect;
if (IsWindow()) {
::GetClientRect(parent_window, &parent_rect);
SetWindowPos(NULL, &parent_rect, SWP_SHOWWINDOW);
return true;
}
// First time in -- no window created by plugin yet.
::GetClientRect(parent_window, &parent_rect);
Create(parent_window, parent_rect, NULL, WS_CHILD | WS_BORDER);
UpdateWindow();
ShowWindow(SW_SHOW);
return true;
}
void ClientPlugin::Shutdown()
{
if (IsWindow()) {
DestroyWindow();
}
}
LRESULT ClientPlugin::OnPaint(UINT message, WPARAM wparam, LPARAM lparam,
BOOL& handled)
{
static LPCWSTR text = L"Left click in the green area for a message box!";
PAINTSTRUCT paint_struct;
BeginPaint(&paint_struct);
RECT client_rect;
GetClientRect(&client_rect);
int old_mode = SetBkMode(paint_struct.hdc, TRANSPARENT);
COLORREF old_color = SetTextColor(paint_struct.hdc, RGB(0, 0, 255));
RECT text_rect = client_rect;
DrawText(paint_struct.hdc, text, -1, &text_rect, DT_CENTER | DT_CALCRECT);
client_rect.top = ((client_rect.bottom - client_rect.top)
- (text_rect.bottom - text_rect.top)) / 2;
DrawText(paint_struct.hdc, text, -1, &client_rect, DT_CENTER);
SetBkMode(paint_struct.hdc, old_mode);
SetTextColor(paint_struct.hdc, old_color);
EndPaint(&paint_struct);
return 0;
}
LRESULT ClientPlugin::OnEraseBackGround(UINT message, WPARAM wparam,
LPARAM lparam, BOOL& handled)
{
HDC paint_device_context = reinterpret_cast<HDC>(wparam);
RECT erase_rect;
GetClipBox(paint_device_context, &erase_rect);
HBRUSH brush = CreateSolidBrush(RGB(0, 255, 0));
FillRect(paint_device_context, &erase_rect, brush);
DeleteObject(brush);
return 1;
}
LRESULT ClientPlugin::OnLButtonDown(UINT message, WPARAM wparam, LPARAM lparam,
BOOL& handled)
{
MessageBox(L"You clicked on the client plugin!", L"Client Plugin", MB_OK);
return 0;
}
void ClientPlugin::RefreshDisplay() {
if (!IsWindow())
return;
InvalidateRect(NULL, TRUE);
UpdateWindow();
}

View File

@ -0,0 +1,103 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Portions of this implementation are borrowed from webkit\default_plugin\
// plugin_impl.h
#pragma once
#include <atlbase.h>
#include <atlwin.h>
#include "cef_nplugin.h"
extern NPNetscapeFuncs* g_browser;
NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* pFuncs);
NPError API_CALL NP_Initialize(NPNetscapeFuncs* pFuncs);
NPError API_CALL NP_Shutdown(void);
// Structure providing information about the client plugin.
const CefPluginInfo ClientPluginInfo = {
{
L"client_plugin",
L"Client Plugin",
L"My Example Client Plugin",
L"1, 0, 0, 1",
L"application/x-client-plugin",
L"*",
L""
},
NP_GetEntryPoints,
NP_Initialize,
NP_Shutdown
};
// Provides the client plugin functionality.
class ClientPlugin : public CWindowImpl<ClientPlugin> {
public:
// mode is the plugin instantiation mode, i.e. whether it is a full
// page plugin (NP_FULL) or an embedded plugin (NP_EMBED)
explicit ClientPlugin(int16 mode);
virtual ~ClientPlugin();
BEGIN_MSG_MAP(ClientPlugin)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackGround)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
END_MSG_MAP()
// Initializes the plugin with the instance information, mime type
// and the list of parameters passed down to the plugin from the webpage.
//
// Parameters:
// module_handle
// The handle to the dll in which this object is instantiated.
// instance
// The plugins opaque instance handle.
// mime_type
// Identifies the third party plugin which would be eventually installed.
// argc
// Indicates the count of arguments passed in from the webpage.
// argv
// Pointer to the arguments.
// Returns true on success.
bool Initialize(HINSTANCE module_handle, NPP instance, NPMIMEType mime_type,
int16 argc, char* argn[], char* argv[]);
// Displays the default plugin UI.
//
// Parameters:
// parent_window
// Handle to the parent window.
bool SetWindow(HWND parent_window);
// Destroys the install dialog and the plugin window.
void Shutdown();
HWND window() const { return m_hWnd; }
// Getter for the NPP instance member.
const NPP instance() const {
return instance_;
}
protected:
// Window message handlers.
LRESULT OnPaint(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
LRESULT OnEraseBackGround(UINT message, WPARAM wparam, LPARAM lparam,
BOOL& handled);
LRESULT OnLButtonDown(UINT message, WPARAM wparam, LPARAM lparam,
BOOL& handled);
// Enables the plugin window if required and initiates an update of the
// the plugin window.
void RefreshDisplay();
private:
// The plugins opaque instance handle
NPP instance_;
// The plugin instantiation mode (NP_FULL or NP_EMBED)
int16 mode_;
};

View File

@ -22,6 +22,7 @@
#define IDC_NAV_RELOAD 202
#define IDC_NAV_STOP 203
#define ID_TESTS_JAVASCRIPT 32771
#define ID_TESTS_PLUGIN 32772
#define IDC_STATIC -1
#define IDS_LOGO 1000
@ -31,7 +32,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 130
#define _APS_NEXT_COMMAND_VALUE 32772
#define _APS_NEXT_COMMAND_VALUE 32773
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif