summaryrefslogtreecommitdiffstats
path: root/webkit/glue/plugins/plugin_host.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/glue/plugins/plugin_host.cc')
-rw-r--r--webkit/glue/plugins/plugin_host.cc1088
1 files changed, 1088 insertions, 0 deletions
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc
new file mode 100644
index 0000000..fe1d7ef
--- /dev/null
+++ b/webkit/glue/plugins/plugin_host.cc
@@ -0,0 +1,1088 @@
+// Copyright (c) 2010 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 "webkit/glue/plugins/plugin_host.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"
+#if defined(OS_MACOSX)
+#include "base/sys_info.h"
+#endif
+#include "base/sys_string_conversions.h"
+#include "net/base/net_util.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/default_plugin_shared.h"
+#include "webkit/glue/plugins/npapi_extension_thunk.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/glue/plugins/plugin_stream_url.h"
+#include "webkit/glue/plugins/webplugin_delegate.h"
+#include "webkit/glue/plugins/webplugininfo.h"
+#include "third_party/npapi/bindings/npapi_extensions.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+using WebKit::WebBindings;
+
+// Finds a PluginInstance from an NPP.
+// The caller must take a reference if needed.
+static NPAPI::PluginInstance* FindInstance(NPP id) {
+ if (id == NULL) {
+ NOTREACHED();
+ return NULL;
+ }
+ return reinterpret_cast<NPAPI::PluginInstance*>(id->ndata);
+}
+
+#if defined(OS_MACOSX)
+// Returns true if the OS supports shared accelerated surfaces via IOSurface.
+// This is true on Snow Leopard and higher.
+static bool SupportsSharingAcceleratedSurfaces() {
+ int32 major, minor, bugfix;
+ base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+ return major > 10 || (major == 10 && minor > 5);
+}
+#endif
+
+namespace NPAPI {
+
+scoped_refptr<PluginHost> PluginHost::singleton_;
+
+PluginHost::PluginHost() {
+ InitializeHostFuncs();
+}
+
+PluginHost::~PluginHost() {
+}
+
+PluginHost *PluginHost::Singleton() {
+ if (singleton_.get() == NULL) {
+ singleton_ = new PluginHost();
+ }
+
+ DCHECK(singleton_.get() != NULL);
+ return singleton_;
+}
+
+void PluginHost::InitializeHostFuncs() {
+ memset(&host_funcs_, 0, sizeof(host_funcs_));
+ host_funcs_.size = sizeof(host_funcs_);
+ host_funcs_.version = (NP_VERSION_MAJOR << 8) | (NP_VERSION_MINOR);
+
+ // The "basic" functions
+ host_funcs_.geturl = &NPN_GetURL;
+ host_funcs_.posturl = &NPN_PostURL;
+ host_funcs_.requestread = &NPN_RequestRead;
+ host_funcs_.newstream = &NPN_NewStream;
+ host_funcs_.write = &NPN_Write;
+ host_funcs_.destroystream = &NPN_DestroyStream;
+ host_funcs_.status = &NPN_Status;
+ host_funcs_.uagent = &NPN_UserAgent;
+ host_funcs_.memalloc = &NPN_MemAlloc;
+ host_funcs_.memfree = &NPN_MemFree;
+ host_funcs_.memflush = &NPN_MemFlush;
+ host_funcs_.reloadplugins = &NPN_ReloadPlugins;
+
+ // We don't implement java yet
+ host_funcs_.getJavaEnv = &NPN_GetJavaEnv;
+ host_funcs_.getJavaPeer = &NPN_GetJavaPeer;
+
+ // Advanced functions we implement
+ host_funcs_.geturlnotify = &NPN_GetURLNotify;
+ host_funcs_.posturlnotify = &NPN_PostURLNotify;
+ host_funcs_.getvalue = &NPN_GetValue;
+ host_funcs_.setvalue = &NPN_SetValue;
+ host_funcs_.invalidaterect = &NPN_InvalidateRect;
+ host_funcs_.invalidateregion = &NPN_InvalidateRegion;
+ host_funcs_.forceredraw = &NPN_ForceRedraw;
+
+ // These come from the Javascript Engine
+ host_funcs_.getstringidentifier = WebBindings::getStringIdentifier;
+ host_funcs_.getstringidentifiers = WebBindings::getStringIdentifiers;
+ host_funcs_.getintidentifier = WebBindings::getIntIdentifier;
+ host_funcs_.identifierisstring = WebBindings::identifierIsString;
+ host_funcs_.utf8fromidentifier = WebBindings::utf8FromIdentifier;
+ host_funcs_.intfromidentifier = WebBindings::intFromIdentifier;
+ host_funcs_.createobject = WebBindings::createObject;
+ host_funcs_.retainobject = WebBindings::retainObject;
+ host_funcs_.releaseobject = WebBindings::releaseObject;
+ host_funcs_.invoke = WebBindings::invoke;
+ host_funcs_.invokeDefault = WebBindings::invokeDefault;
+ host_funcs_.evaluate = WebBindings::evaluate;
+ host_funcs_.getproperty = WebBindings::getProperty;
+ host_funcs_.setproperty = WebBindings::setProperty;
+ host_funcs_.removeproperty = WebBindings::removeProperty;
+ host_funcs_.hasproperty = WebBindings::hasProperty;
+ host_funcs_.hasmethod = WebBindings::hasMethod;
+ host_funcs_.releasevariantvalue = WebBindings::releaseVariantValue;
+ host_funcs_.setexception = WebBindings::setException;
+ host_funcs_.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
+ host_funcs_.poppopupsenabledstate = NPN_PopPopupsEnabledState;
+ host_funcs_.enumerate = WebBindings::enumerate;
+ host_funcs_.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
+ host_funcs_.construct = WebBindings::construct;
+ host_funcs_.getvalueforurl = NPN_GetValueForURL;
+ host_funcs_.setvalueforurl = NPN_SetValueForURL;
+ host_funcs_.getauthenticationinfo = NPN_GetAuthenticationInfo;
+ host_funcs_.scheduletimer = NPN_ScheduleTimer;
+ host_funcs_.unscheduletimer = NPN_UnscheduleTimer;
+ host_funcs_.popupcontextmenu = NPN_PopUpContextMenu;
+ host_funcs_.convertpoint = NPN_ConvertPoint;
+}
+
+void PluginHost::PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides) {
+ // When running in the plugin process, we need to patch the NPN functions
+ // that the plugin calls to interact with NPObjects that we give. Otherwise
+ // the plugin will call the v8 NPN functions, which won't work since we have
+ // an NPObjectProxy and not a real v8 implementation.
+ if (overrides->invoke)
+ host_funcs_.invoke = overrides->invoke;
+
+ if (overrides->invokeDefault)
+ host_funcs_.invokeDefault = overrides->invokeDefault;
+
+ if (overrides->evaluate)
+ host_funcs_.evaluate = overrides->evaluate;
+
+ if (overrides->getproperty)
+ host_funcs_.getproperty = overrides->getproperty;
+
+ if (overrides->setproperty)
+ host_funcs_.setproperty = overrides->setproperty;
+
+ if (overrides->removeproperty)
+ host_funcs_.removeproperty = overrides->removeproperty;
+
+ if (overrides->hasproperty)
+ host_funcs_.hasproperty = overrides->hasproperty;
+
+ if (overrides->hasmethod)
+ host_funcs_.hasmethod = overrides->hasmethod;
+
+ if (overrides->setexception)
+ host_funcs_.setexception = overrides->setexception;
+
+ if (overrides->enumerate)
+ host_funcs_.enumerate = overrides->enumerate;
+}
+
+bool PluginHost::SetPostData(const char* buf,
+ uint32 length,
+ std::vector<std::string>* names,
+ std::vector<std::string>* values,
+ std::vector<char>* body) {
+ // Use a state table to do the parsing. Whitespace must be
+ // trimmed after the fact if desired. In our case, we actually
+ // don't care about the whitespace, because we're just going to
+ // pass this back into another POST. This function strips out the
+ // "Content-length" header and does not append it to the request.
+
+ //
+ // This parser takes action only on state changes.
+ //
+ // Transition table:
+ // : \n NULL Other
+ // 0 GetHeader 1 2 4 0
+ // 1 GetValue 1 0 3 1
+ // 2 GetData 2 2 3 2
+ // 3 DONE
+ // 4 ERR
+ //
+ enum { INPUT_COLON=0, INPUT_NEWLINE, INPUT_NULL, INPUT_OTHER };
+ enum { GETNAME, GETVALUE, GETDATA, DONE, ERR };
+ int statemachine[3][4] = { { GETVALUE, GETDATA, GETDATA, GETNAME },
+ { GETVALUE, GETNAME, DONE, GETVALUE },
+ { GETDATA, GETDATA, DONE, GETDATA } };
+ std::string name, value;
+ const char* ptr = static_cast<const char*>(buf);
+ const char* start = ptr;
+ int state = GETNAME; // initial state
+ bool done = false;
+ bool err = false;
+ do {
+ int input;
+
+ // Translate the current character into an input
+ // for the state table.
+ switch (*ptr) {
+ case ':' :
+ input = INPUT_COLON;
+ break;
+ case '\n':
+ input = INPUT_NEWLINE;
+ break;
+ case 0 :
+ input = INPUT_NULL;
+ break;
+ default :
+ input = INPUT_OTHER;
+ break;
+ }
+
+ int newstate = statemachine[state][input];
+
+ // Take action based on the new state.
+ if (state != newstate) {
+ switch (newstate) {
+ case GETNAME:
+ // Got a value.
+ value = std::string(start, ptr - start);
+ TrimWhitespace(value, TRIM_ALL, &value);
+ // If the name field is empty, we'll skip this header
+ // but we won't error out.
+ if (!name.empty() && name != "content-length") {
+ names->push_back(name);
+ values->push_back(value);
+ }
+ start = ptr + 1;
+ break;
+ case GETVALUE:
+ // Got a header.
+ name = StringToLowerASCII(std::string(start, ptr - start));
+ TrimWhitespace(name, TRIM_ALL, &name);
+ start = ptr + 1;
+ break;
+ case GETDATA: {
+ // Finished headers, now get body
+ if (*ptr)
+ start = ptr + 1;
+ size_t previous_size = body->size();
+ size_t new_body_size = length - static_cast<int>(start - buf);
+ body->resize(previous_size + new_body_size);
+ if (!body->empty())
+ memcpy(&body->front() + previous_size, start, new_body_size);
+ done = true;
+ break;
+ }
+ case ERR:
+ // error
+ err = true;
+ done = true;
+ break;
+ }
+ }
+ state = newstate;
+ ptr++;
+ } while (!done);
+
+ return !err;
+}
+
+} // namespace NPAPI
+
+extern "C" {
+
+// Allocates memory from the host's memory space.
+void* NPN_MemAlloc(uint32_t size) {
+ scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton();
+ if (host != NULL) {
+ // Note: We must use the same allocator/deallocator
+ // that is used by the javascript library, as some of the
+ // JS APIs will pass memory to the plugin which the plugin
+ // will attempt to free.
+ return malloc(size);
+ }
+ return NULL;
+}
+
+// Deallocates memory from the host's memory space
+void NPN_MemFree(void* ptr) {
+ scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton();
+ if (host != NULL) {
+ if (ptr != NULL && ptr != reinterpret_cast<void*>(-1))
+ free(ptr);
+ }
+}
+
+// Requests that the host free a specified amount of memory.
+uint32_t NPN_MemFlush(uint32_t size) {
+ // This is not relevant on Windows; MAC specific
+ return size;
+}
+
+// This is for dynamic discovery of new plugins.
+// Should force a re-scan of the plugins directory to load new ones.
+void NPN_ReloadPlugins(NPBool reloadPages) {
+ // TODO: implement me
+ DLOG(INFO) << "NPN_ReloadPlugin is not implemented yet.";
+}
+
+// Requests a range of bytes for a seekable stream.
+NPError NPN_RequestRead(NPStream* stream, NPByteRange* range_list) {
+ if (!stream || !range_list)
+ return NPERR_GENERIC_ERROR;
+
+ scoped_refptr<NPAPI::PluginInstance> plugin =
+ reinterpret_cast<NPAPI::PluginInstance*>(stream->ndata);
+ if (!plugin.get())
+ return NPERR_GENERIC_ERROR;
+
+ plugin->RequestRead(stream, range_list);
+ return NPERR_NO_ERROR;
+}
+
+// Generic form of GetURL for common code between GetURL and GetURLNotify.
+static NPError GetURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ bool notify,
+ void* notify_data) {
+ if (!url)
+ return NPERR_INVALID_URL;
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (!plugin.get()) {
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ plugin->RequestURL(url, "GET", target, NULL, 0, notify, notify_data);
+ return NPERR_NO_ERROR;
+}
+
+// Requests creation of a new stream with the contents of the
+// specified URL; gets notification of the result.
+NPError NPN_GetURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ void* notify_data) {
+ // This is identical to NPN_GetURL, but after finishing, the
+ // browser will call NPP_URLNotify to inform the plugin that
+ // it has completed.
+
+ // According to the NPAPI documentation, if target == _self
+ // or a parent to _self, the browser should return NPERR_INVALID_PARAM,
+ // because it can't notify the plugin once deleted. This is
+ // absolutely false; firefox doesn't do this, and Flash relies on
+ // being able to use this.
+
+ // Also according to the NPAPI documentation, we should return
+ // NPERR_INVALID_URL if the url requested is not valid. However,
+ // this would require that we synchronously start fetching the
+ // URL. That just isn't practical. As such, there really is
+ // no way to return this error. From looking at the Firefox
+ // implementation, it doesn't look like Firefox does this either.
+
+ return GetURLNotify(id, url, target, true, notify_data);
+}
+
+NPError NPN_GetURL(NPP id, const char* url, const char* target) {
+ // Notes:
+ // Request from the Plugin to fetch content either for the plugin
+ // or to be placed into a browser window.
+ //
+ // If target == null, the browser fetches content and streams to plugin.
+ // otherwise, the browser loads content into an existing browser frame.
+ // If the target is the window/frame containing the plugin, the plugin
+ // may be destroyed.
+ // If the target is _blank, a mailto: or news: url open content in a new
+ // browser window
+ // If the target is _self, no other instance of the plugin is created. The
+ // plugin continues to operate in its own window
+
+ return GetURLNotify(id, url, target, false, 0);
+}
+
+// Generic form of PostURL for common code between PostURL and PostURLNotify.
+static NPError PostURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ uint32_t len,
+ const char* buf,
+ NPBool file,
+ bool notify,
+ void* notify_data) {
+ if (!url)
+ return NPERR_INVALID_URL;
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (!plugin.get()) {
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ std::string post_file_contents;
+
+ if (file) {
+ // Post data to be uploaded from a file. This can be handled in two
+ // ways.
+ // 1. Read entire file and send the contents as if it was a post data
+ // specified in the argument
+ // 2. Send just the file details and read them in the browser at the
+ // time of sending the request.
+ // Approach 2 is more efficient but complicated. Approach 1 has a major
+ // drawback of sending potentially large data over two IPC hops. In a way
+ // 'large data over IPC' problem exists as it is in case of plugin giving
+ // the data directly instead of in a file.
+ // Currently we are going with the approach 1 to get the feature working.
+ // We can optimize this later with approach 2.
+
+ // TODO(joshia): Design a scheme to send a file descriptor instead of
+ // entire file contents across.
+
+ // Security alert:
+ // ---------------
+ // Here we are blindly uploading whatever file requested by a plugin.
+ // This is risky as someone could exploit a plugin to send private
+ // data in arbitrary locations.
+ // A malicious (non-sandboxed) plugin has unfeterred access to OS
+ // resources and can do this anyway without using browser's HTTP stack.
+ // FWIW, Firefox and Safari don't perform any security checks.
+
+ if (!buf)
+ return NPERR_FILE_NOT_FOUND;
+
+ std::string file_path_ascii(buf);
+ FilePath file_path;
+ static const char kFileUrlPrefix[] = "file:";
+ if (StartsWithASCII(file_path_ascii, kFileUrlPrefix, false)) {
+ GURL file_url(file_path_ascii);
+ DCHECK(file_url.SchemeIsFile());
+ net::FileURLToFilePath(file_url, &file_path);
+ } else {
+ file_path = FilePath::FromWStringHack(
+ base::SysNativeMBToWide(file_path_ascii));
+ }
+
+ file_util::FileInfo post_file_info = {0};
+ if (!file_util::GetFileInfo(file_path, &post_file_info) ||
+ post_file_info.is_directory)
+ return NPERR_FILE_NOT_FOUND;
+
+ if (!file_util::ReadFileToString(file_path, &post_file_contents))
+ return NPERR_FILE_NOT_FOUND;
+
+ buf = post_file_contents.c_str();
+ len = post_file_contents.size();
+ }
+
+ // The post data sent by a plugin contains both headers
+ // and post data. Example:
+ // Content-type: text/html
+ // Content-length: 200
+ //
+ // <200 bytes of content here>
+ //
+ // Unfortunately, our stream needs these broken apart,
+ // so we need to parse the data and set headers and data
+ // separately.
+ plugin->RequestURL(url, "POST", target, buf, len, notify, notify_data);
+ return NPERR_NO_ERROR;
+}
+
+NPError NPN_PostURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ uint32_t len,
+ const char* buf,
+ NPBool file,
+ void* notify_data) {
+ return PostURLNotify(id, url, target, len, buf, file, true, notify_data);
+}
+
+NPError NPN_PostURL(NPP id,
+ const char* url,
+ const char* target,
+ uint32_t len,
+ const char* buf,
+ NPBool file) {
+ // POSTs data to an URL, either from a temp file or a buffer.
+ // If file is true, buf contains a temp file (which host will delete after
+ // completing), and len contains the length of the filename.
+ // If file is false, buf contains the data to send, and len contains the
+ // length of the buffer
+ //
+ // If target is null,
+ // server response is returned to the plugin
+ // If target is _current, _self, or _top,
+ // server response is written to the plugin window and plugin is unloaded.
+ // If target is _new or _blank,
+ // server response is written to a new browser window
+ // If target is an existing frame,
+ // server response goes to that frame.
+ //
+ // For protocols other than FTP
+ // file uploads must be line-end converted from \r\n to \n
+ //
+ // Note: you cannot specify headers (even a blank line) in a memory buffer,
+ // use NPN_PostURLNotify
+
+ return PostURLNotify(id, url, target, len, buf, file, false, 0);
+}
+
+NPError NPN_NewStream(NPP id,
+ NPMIMEType type,
+ const char* target,
+ NPStream** stream) {
+ // Requests creation of a new data stream produced by the plugin,
+ // consumed by the browser.
+ //
+ // Browser should put this stream into a window target.
+ //
+ // TODO: implement me
+ DLOG(INFO) << "NPN_NewStream is not implemented yet.";
+ return NPERR_GENERIC_ERROR;
+}
+
+int32_t NPN_Write(NPP id, NPStream* stream, int32_t len, void* buffer) {
+ // Writes data to an existing Plugin-created stream.
+
+ // TODO: implement me
+ DLOG(INFO) << "NPN_Write is not implemented yet.";
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPN_DestroyStream(NPP id, NPStream* stream, NPReason reason) {
+ // Destroys a stream (could be created by plugin or browser).
+ //
+ // Reasons:
+ // NPRES_DONE - normal completion
+ // NPRES_USER_BREAK - user terminated
+ // NPRES_NETWORK_ERROR - network error (all errors fit here?)
+ //
+ //
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get() == NULL) {
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ return plugin->NPP_DestroyStream(stream, reason);
+}
+
+const char* NPN_UserAgent(NPP id) {
+#if defined(OS_WIN)
+ // Flash passes in a null id during the NP_initialize call. We need to
+ // default to the Mozilla user agent if we don't have an NPP instance or
+ // else Flash won't request windowless mode.
+ bool use_mozilla_user_agent = true;
+ if (id) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get() && !plugin->use_mozilla_user_agent())
+ use_mozilla_user_agent = false;
+ }
+
+ if (use_mozilla_user_agent)
+ return "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) "
+ "Gecko/20061103 Firefox/2.0a1";
+#elif defined(OS_MACOSX)
+ // Silverlight 4 doesn't handle events correctly unless we claim to be Safari.
+ scoped_refptr<NPAPI::PluginInstance> plugin;
+ if (id)
+ plugin = FindInstance(id);
+ if (plugin.get()) {
+ WebPluginInfo plugin_info = plugin->plugin_lib()->plugin_info();
+ if (plugin_info.name == ASCIIToUTF16("Silverlight Plug-In") &&
+ StartsWith(plugin_info.version, ASCIIToUTF16("4."), false)) {
+ return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) "
+ "AppleWebKit/534.1+ (KHTML, like Gecko) Version/5.0 Safari/533.16";
+ }
+ }
+#endif
+
+ return webkit_glue::GetUserAgent(GURL()).c_str();
+}
+
+void NPN_Status(NPP id, const char* message) {
+ // Displays a message on the status line of the browser window.
+
+ // TODO: implement me
+ DLOG(INFO) << "NPN_Status is not implemented yet.";
+}
+
+void NPN_InvalidateRect(NPP id, NPRect *invalidRect) {
+ // Invalidates specified drawing area prior to repainting or refreshing a
+ // windowless plugin
+
+ // Before a windowless plugin can refresh part of its drawing area, it must
+ // first invalidate it. This function causes the NPP_HandleEvent method to
+ // pass an update event or a paint message to the plug-in. After calling
+ // this method, the plug-in recieves a paint message asynchronously.
+
+ // The browser redraws invalid areas of the document and any windowless
+ // plug-ins at regularly timed intervals. To force a paint message, the
+ // plug-in can call NPN_ForceRedraw after calling this method.
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ DCHECK(plugin.get() != NULL);
+ if (plugin.get() && plugin->webplugin()) {
+ if (invalidRect) {
+#if defined(OS_WIN)
+ if (!plugin->windowless()) {
+ RECT rect = {0};
+ rect.left = invalidRect->left;
+ rect.right = invalidRect->right;
+ rect.top = invalidRect->top;
+ rect.bottom = invalidRect->bottom;
+ ::InvalidateRect(plugin->window_handle(), &rect, false);
+ return;
+ }
+#endif
+ gfx::Rect rect(invalidRect->left,
+ invalidRect->top,
+ invalidRect->right - invalidRect->left,
+ invalidRect->bottom - invalidRect->top);
+ plugin->webplugin()->InvalidateRect(rect);
+ } else {
+ plugin->webplugin()->Invalidate();
+ }
+ }
+}
+
+void NPN_InvalidateRegion(NPP id, NPRegion invalidRegion) {
+ // Invalidates a specified drawing region prior to repainting
+ // or refreshing a window-less plugin.
+ //
+ // Similar to NPN_InvalidateRect.
+
+ // TODO: this is overkill--add platform-specific region handling (at the
+ // very least, fetch the region's bounding box and pass it to InvalidateRect).
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ DCHECK(plugin.get() != NULL);
+ if (plugin.get() && plugin->webplugin())
+ plugin->webplugin()->Invalidate();
+}
+
+void NPN_ForceRedraw(NPP id) {
+ // Forces repaint for a windowless plug-in.
+ //
+ // We deliberately do not implement this; we don't want plugins forcing
+ // synchronous paints.
+}
+
+NPError NPN_GetValue(NPP id, NPNVariable variable, void* value) {
+ // Allows the plugin to query the browser for information
+ //
+ // Variables:
+ // NPNVxDisplay (unix only)
+ // NPNVxtAppContext (unix only)
+ // NPNVnetscapeWindow (win only) - Gets the native window on which the
+ // plug-in drawing occurs, returns HWND
+ // NPNVjavascriptEnabledBool: tells whether Javascript is enabled
+ // NPNVasdEnabledBool: tells whether SmartUpdate is enabled
+ // NPNVOfflineBool: tells whether offline-mode is enabled
+
+ NPError rv = NPERR_GENERIC_ERROR;
+
+ switch (static_cast<int>(variable)) {
+ case NPNVWindowNPObject: {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ NPObject *np_object = plugin->webplugin()->GetWindowScriptNPObject();
+ // Return value is expected to be retained, as
+ // described here:
+ // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
+ if (np_object) {
+ WebBindings::retainObject(np_object);
+ void **v = (void **)value;
+ *v = np_object;
+ rv = NPERR_NO_ERROR;
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
+ case NPNVPluginElementNPObject: {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ NPObject *np_object = plugin->webplugin()->GetPluginElement();
+ // Return value is expected to be retained, as
+ // described here:
+ // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
+ if (np_object) {
+ WebBindings::retainObject(np_object);
+ void** v = static_cast<void**>(value);
+ *v = np_object;
+ rv = NPERR_NO_ERROR;
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
+ #if !defined(OS_MACOSX) // OS X doesn't have windowed plugins.
+ case NPNVnetscapeWindow: {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (!plugin.get()) {
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+ gfx::PluginWindowHandle handle = plugin->window_handle();
+ *((void**)value) = (void*)handle;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ #endif
+ case NPNVjavascriptEnabledBool: {
+ // yes, JS is enabled.
+ *((void**)value) = (void*)1;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ #if defined(TOOLKIT_USES_GTK)
+ case NPNVToolkit:
+ // Tell them we are GTK2. (The alternative is GTK 1.2.)
+ *reinterpret_cast<int*>(value) = NPNVGtk2;
+ rv = NPERR_NO_ERROR;
+ break;
+
+ case NPNVSupportsXEmbedBool:
+ *reinterpret_cast<NPBool*>(value) = true;
+ rv = NPERR_NO_ERROR;
+ break;
+ #endif
+ case NPNVSupportsWindowless: {
+ NPBool* supports_windowless = reinterpret_cast<NPBool*>(value);
+ *supports_windowless = true;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case NPNVprivateModeBool: {
+ NPBool* private_mode = reinterpret_cast<NPBool*>(value);
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ *private_mode = plugin->webplugin()->IsOffTheRecord();
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case default_plugin::kMissingPluginStatusStart +
+ default_plugin::MISSING_PLUGIN_AVAILABLE:
+ // fall through
+ case default_plugin::kMissingPluginStatusStart +
+ default_plugin::MISSING_PLUGIN_USER_STARTED_DOWNLOAD: {
+ // This is a hack for the default plugin to send notification to
+ // renderer. Even though we check if the plugin is the default plugin,
+ // we still need to worry about future standard change that may conflict
+ // with the variable definition, in order to avoid duplicate case clauses
+ // in this big switch statement.
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin->plugin_lib()->plugin_info().path.value() ==
+ kDefaultPluginLibraryName) {
+ plugin->webplugin()->OnMissingPluginStatus(
+ variable - default_plugin::kMissingPluginStatusStart);
+ }
+ break;
+ }
+ #if defined(OS_MACOSX)
+ case NPNVpluginDrawingModel: {
+ // return the drawing model that was negotiated when we initialized.
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ *reinterpret_cast<int*>(value) = plugin->drawing_model();
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+#ifndef NP_NO_QUICKDRAW
+ case NPNVsupportsQuickDrawBool: {
+ // We do not admit to supporting the QuickDraw drawing model. The logic
+ // here is that our QuickDraw plugin support is so rudimentary that we
+ // only want to use it as a fallback to keep plugins from crashing: if a
+ // plugin knows enough to ask, we want them to use CoreGraphics.
+ NPBool* supports_qd = reinterpret_cast<NPBool*>(value);
+ *supports_qd = false;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+#endif
+ case NPNVsupportsCoreGraphicsBool:
+#ifndef NP_NO_CARBON
+ case NPNVsupportsCarbonBool:
+#endif
+ case NPNVsupportsCocoaBool: {
+ // we do support these drawing and event models.
+ NPBool* supports_model = reinterpret_cast<NPBool*>(value);
+ *supports_model = true;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case NPNVsupportsCoreAnimationBool:
+ case NPNVsupportsInvalidatingCoreAnimationBool: {
+ // We only support the Core Animation model on 10.6 and higher
+ // TODO(stuartmorgan): Once existing CA plugins have implemented the
+ // invalidating version, remove support for the other version.
+ NPBool* supports_model = reinterpret_cast<NPBool*>(value);
+ *supports_model = SupportsSharingAcceleratedSurfaces() ? true : false;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case NPNVsupportsOpenGLBool: {
+ // This drawing model was never widely supported, and we don't plan to
+ // support it.
+ NPBool* supports_model = reinterpret_cast<NPBool*>(value);
+ *supports_model = false;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ #endif // OS_MACOSX
+ case NPNVPepperExtensions:
+ // Available for any plugin that attempts to get it.
+ // If the plugin is not started in a Pepper implementation, it
+ // will likely fail when it tries to use any of the functions
+ // attached to the extension vector.
+ rv = NPAPI::GetPepperExtensionsFunctions(value);
+ break;
+ default:
+ DLOG(INFO) << "NPN_GetValue(" << variable << ") is not implemented yet.";
+ break;
+ }
+ return rv;
+}
+
+NPError NPN_SetValue(NPP id, NPPVariable variable, void* value) {
+ // Allows the plugin to set various modes
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ switch(variable) {
+ case NPPVpluginWindowBool: {
+ // Sets windowless mode for display of the plugin
+ // Note: the documentation at
+ // http://developer.mozilla.org/en/docs/NPN_SetValue is wrong. When
+ // value is NULL, the mode is set to true. This is the same way Mozilla
+ // works.
+ plugin->set_windowless(value == 0);
+ return NPERR_NO_ERROR;
+ }
+ case NPPVpluginTransparentBool: {
+ // Sets transparent mode for display of the plugin
+ //
+ // Transparent plugins require the browser to paint the background
+ // before having the plugin paint. By default, windowless plugins
+ // are transparent. Making a windowless plugin opaque means that
+ // the plugin does not require the browser to paint the background.
+ bool mode = (value != 0);
+ plugin->set_transparent(mode);
+ return NPERR_NO_ERROR;
+ }
+ case NPPVjavascriptPushCallerBool:
+ // Specifies whether you are pushing or popping the JSContext off.
+ // the stack
+ // TODO: implement me
+ DLOG(INFO) <<
+ "NPN_SetValue(NPPVJavascriptPushCallerBool) is not implemented.";
+ return NPERR_GENERIC_ERROR;
+ case NPPVpluginKeepLibraryInMemory:
+ // Tells browser that plugin library should live longer than usual.
+ // TODO: implement me
+ DLOG(INFO) <<
+ "NPN_SetValue(NPPVpluginKeepLibraryInMemory) is not implemented.";
+ return NPERR_GENERIC_ERROR;
+ #if defined(OS_MACOSX)
+ case NPPVpluginDrawingModel: {
+ int model = reinterpret_cast<int>(value);
+ if (model == NPDrawingModelCoreGraphics) {
+ plugin->set_drawing_model(static_cast<NPDrawingModel>(model));
+ return NPERR_NO_ERROR;
+ } else if ((model == NPDrawingModelCoreAnimation ||
+ model == NPDrawingModelInvalidatingCoreAnimation) &&
+ SupportsSharingAcceleratedSurfaces()) {
+ plugin->set_drawing_model(static_cast<NPDrawingModel>(model));
+ return NPERR_NO_ERROR;
+ }
+ return NPERR_GENERIC_ERROR;
+ }
+ case NPPVpluginEventModel: {
+ // we support Carbon and Cocoa event models
+ int model = reinterpret_cast<int>(value);
+ switch (model) {
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon:
+#endif
+ case NPEventModelCocoa:
+ plugin->set_event_model(static_cast<NPEventModel>(model));
+ return NPERR_NO_ERROR;
+ break;
+ }
+ return NPERR_GENERIC_ERROR;
+ }
+ #endif
+ default:
+ // TODO: implement me
+ DLOG(INFO) << "NPN_SetValue(" << variable << ") is not implemented.";
+ break;
+ }
+
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+}
+
+void* NPN_GetJavaEnv() {
+ // TODO: implement me
+ DLOG(INFO) << "NPN_GetJavaEnv is not implemented.";
+ return NULL;
+}
+
+void* NPN_GetJavaPeer(NPP) {
+ // TODO: implement me
+ DLOG(INFO) << "NPN_GetJavaPeer is not implemented.";
+ return NULL;
+}
+
+void NPN_PushPopupsEnabledState(NPP id, NPBool enabled) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin)
+ plugin->PushPopupsEnabledState(enabled ? true : false);
+}
+
+void NPN_PopPopupsEnabledState(NPP id) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin)
+ plugin->PopPopupsEnabledState();
+}
+
+void NPN_PluginThreadAsyncCall(NPP id,
+ void (*func)(void*),
+ void* user_data) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin)
+ plugin->PluginThreadAsyncCall(func, user_data);
+}
+
+NPError NPN_GetValueForURL(NPP id,
+ NPNURLVariable variable,
+ const char* url,
+ char** value,
+ uint32_t* len) {
+ if (!id)
+ return NPERR_INVALID_PARAM;
+
+ if (!url || !*url || !len)
+ return NPERR_INVALID_URL;
+
+ *len = 0;
+ std::string result;
+
+ switch (variable) {
+ case NPNURLVProxy: {
+ result = "DIRECT";
+ if (!webkit_glue::FindProxyForUrl(GURL((std::string(url))), &result))
+ return NPERR_GENERIC_ERROR;
+
+ break;
+ }
+ case NPNURLVCookie: {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (!plugin)
+ return NPERR_GENERIC_ERROR;
+
+ webkit_glue::WebPlugin* webplugin = plugin->webplugin();
+ if (!webplugin)
+ return NPERR_GENERIC_ERROR;
+
+ // Bypass third-party cookie blocking by using the url as the
+ // first_party_for_cookies.
+ GURL cookies_url((std::string(url)));
+ result = webplugin->GetCookies(cookies_url, cookies_url);
+ break;
+ }
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // Allocate this using the NPAPI allocator. The plugin will call
+ // NPN_Free to free this.
+ *value = static_cast<char*>(NPN_MemAlloc(result.length() + 1));
+ base::strlcpy(*value, result.c_str(), result.length() + 1);
+ *len = result.length();
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPN_SetValueForURL(NPP id,
+ NPNURLVariable variable,
+ const char* url,
+ const char* value,
+ uint32_t len) {
+ if (!id)
+ return NPERR_INVALID_PARAM;
+
+ if (!url || !*url)
+ return NPERR_INVALID_URL;
+
+ switch (variable) {
+ case NPNURLVCookie: {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (!plugin)
+ return NPERR_GENERIC_ERROR;
+
+ webkit_glue::WebPlugin* webplugin = plugin->webplugin();
+ if (!webplugin)
+ return NPERR_GENERIC_ERROR;
+
+ std::string cookie(value, len);
+ GURL cookies_url((std::string(url)));
+ webplugin->SetCookie(cookies_url, cookies_url, cookie);
+ return NPERR_NO_ERROR;
+ }
+ case NPNURLVProxy:
+ // We don't support setting proxy values, fall through...
+ break;
+ default:
+ // Fall through and return an error...
+ break;
+ }
+
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPN_GetAuthenticationInfo(NPP id,
+ const char* protocol,
+ const char* host,
+ int32_t port,
+ const char* scheme,
+ const char* realm,
+ char** username,
+ uint32_t* ulen,
+ char** password,
+ uint32_t* plen) {
+ if (!id || !protocol || !host || !scheme || !realm || !username ||
+ !ulen || !password || !plen)
+ return NPERR_INVALID_PARAM;
+
+ // TODO: implement me (bug 23928)
+ return NPERR_GENERIC_ERROR;
+}
+
+uint32_t NPN_ScheduleTimer(NPP id,
+ uint32_t interval,
+ NPBool repeat,
+ void (*func)(NPP id, uint32_t timer_id)) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (!plugin)
+ return 0;
+
+ return plugin->ScheduleTimer(interval, repeat, func);
+}
+
+void NPN_UnscheduleTimer(NPP id, uint32_t timer_id) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin)
+ plugin->UnscheduleTimer(timer_id);
+}
+
+NPError NPN_PopUpContextMenu(NPP id, NPMenu* menu) {
+ if (!menu)
+ return NPERR_INVALID_PARAM;
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get()) {
+ return plugin->PopUpContextMenu(menu);
+ }
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+}
+
+NPBool NPN_ConvertPoint(NPP id, double sourceX, double sourceY,
+ NPCoordinateSpace sourceSpace,
+ double *destX, double *destY,
+ NPCoordinateSpace destSpace) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get()) {
+ return plugin->ConvertPoint(sourceX, sourceY, sourceSpace,
+ destX, destY, destSpace);
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // extern "C"