diff options
Diffstat (limited to 'webkit/glue/plugins/plugin_host.cc')
-rw-r--r-- | webkit/glue/plugins/plugin_host.cc | 1088 |
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" |