| // Copyright (c) 2012 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 "content/child/npapi/plugin_host.h" |
| |
| #include "base/command_line.h" |
| #include "base/files/file_util.h" |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "build/build_config.h" |
| #include "content/child/npapi/plugin_instance.h" |
| #include "content/child/npapi/plugin_lib.h" |
| #include "content/child/npapi/webplugin_delegate.h" |
| #include "content/public/common/content_client.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/user_agent.h" |
| #include "content/public/common/webplugininfo.h" |
| #include "net/base/filename_util.h" |
| #include "third_party/WebKit/public/web/WebBindings.h" |
| #include "third_party/WebKit/public/web/WebKit.h" |
| #include "third_party/npapi/bindings/npruntime.h" |
| #include "ui/gl/gl_implementation.h" |
| #include "ui/gl/gl_surface.h" |
| |
| using blink::WebBindings; |
| |
| // Declarations for stub implementations of deprecated functions, which are no |
| // longer listed in npapi.h. |
| extern "C" { |
| void* NPN_GetJavaEnv(); |
| void* NPN_GetJavaPeer(NPP); |
| } |
| |
| namespace content { |
| |
| // Finds a PluginInstance from an NPP. |
| // The caller must take a reference if needed. |
| static PluginInstance* FindInstance(NPP id) { |
| if (id == NULL) { |
| return NULL; |
| } |
| return reinterpret_cast<PluginInstance*>(id->ndata); |
| } |
| |
| #if defined(OS_MACOSX) |
| // Returns true if Core Animation plugins are supported. This requires that the |
| // OS supports shared accelerated surfaces via IOSurface. This is true on Snow |
| // Leopard and higher. |
| static bool SupportsCoreAnimationPlugins() { |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDisableCoreAnimationPlugins)) |
| return false; |
| // We also need to be running with desktop GL and not the software |
| // OSMesa renderer in order to share accelerated surfaces between |
| // processes. Because on MacOS we lazy-initialize GLSurface in the |
| // renderer process here, ensure we're not also initializing GL somewhere |
| // else, and that we only do this once. |
| static gfx::GLImplementation implementation = gfx::kGLImplementationNone; |
| if (implementation == gfx::kGLImplementationNone) { |
| // Not initialized yet. |
| DCHECK_EQ(implementation, gfx::GetGLImplementation()) |
| << "GL already initialized by someone else to: " |
| << gfx::GetGLImplementation(); |
| if (!gfx::GLSurface::InitializeOneOff()) { |
| return false; |
| } |
| implementation = gfx::GetGLImplementation(); |
| } |
| return (implementation == gfx::kGLImplementationDesktopGL); |
| } |
| #endif |
| |
| PluginHost::PluginHost() { |
| InitializeHostFuncs(); |
| } |
| |
| PluginHost::~PluginHost() { |
| } |
| |
| PluginHost *PluginHost::Singleton() { |
| CR_DEFINE_STATIC_LOCAL(scoped_refptr<PluginHost>, singleton, ()); |
| if (singleton.get() == NULL) { |
| singleton = new PluginHost(); |
| } |
| |
| DCHECK(singleton.get() != NULL); |
| return singleton.get(); |
| } |
| |
| 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; |
| |
| // Stubs for deprecated Java functions |
| 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; |
| host_funcs_.handleevent = NPN_HandleEvent; |
| host_funcs_.unfocusinstance = NPN_UnfocusInstance; |
| host_funcs_.urlredirectresponse = NPN_URLRedirectResponse; |
| } |
| |
| 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); |
| base::TrimWhitespace(value, base::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 = base::ToLowerASCII(base::StringPiece(start, ptr - start)); |
| base::TrimWhitespace(name, base::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 content |
| |
| extern "C" { |
| |
| using content::FindInstance; |
| using content::PluginHost; |
| using content::PluginInstance; |
| using content::WebPlugin; |
| |
| // Allocates memory from the host's memory space. |
| void* NPN_MemAlloc(uint32_t size) { |
| // 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); |
| } |
| |
| // Deallocates memory from the host's memory space |
| void NPN_MemFree(void* ptr) { |
| 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 reload_pages) { |
| blink::resetPluginCache(reload_pages ? true : false); |
| } |
| |
| // Requests a range of bytes for a seekable stream. |
| NPError NPN_RequestRead(NPStream* stream, NPByteRange* range_list) { |
| return NPERR_GENERIC_ERROR; |
| } |
| |
| NPError NPN_GetURLNotify(NPP id, |
| const char* url, |
| const char* target, |
| void* notify_data) { |
| return NPERR_GENERIC_ERROR; |
| } |
| |
| NPError NPN_GetURL(NPP id, const char* url, const char* target) { |
| return NPERR_GENERIC_ERROR; |
| } |
| |
| NPError NPN_PostURLNotify(NPP id, |
| const char* url, |
| const char* target, |
| uint32_t len, |
| const char* buf, |
| NPBool file, |
| void* notify_data) { |
| return NPERR_GENERIC_ERROR; |
| } |
| |
| NPError NPN_PostURL(NPP id, |
| const char* url, |
| const char* target, |
| uint32_t len, |
| const char* buf, |
| NPBool file) { |
| return NPERR_GENERIC_ERROR; |
| } |
| |
| 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 |
| DVLOG(1) << "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 |
| DVLOG(1) << "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<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<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"; |
| #endif |
| |
| // Provide a consistent user-agent string with memory that lasts |
| // long enough for the caller to read it. |
| static base::LazyInstance<std::string>::Leaky leaky_user_agent = |
| LAZY_INSTANCE_INITIALIZER; |
| if (leaky_user_agent == NULL) |
| leaky_user_agent.Get() = content::GetContentClient()->GetUserAgent(); |
| return leaky_user_agent.Get().c_str(); |
| } |
| |
| void NPN_Status(NPP id, const char* message) { |
| // Displays a message on the status line of the browser window. |
| |
| // TODO: implement me |
| DVLOG(1) << "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 plugin. After calling |
| // this method, the plugin receives a paint message asynchronously. |
| |
| // The browser redraws invalid areas of the document and any windowless |
| // plugins at regularly timed intervals. To force a paint message, the |
| // plugin can call NPN_ForceRedraw after calling this method. |
| |
| scoped_refptr<PluginInstance> plugin(FindInstance(id)); |
| 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<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 plugin. |
| // |
| // 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 |
| // plugin 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<PluginInstance> plugin(FindInstance(id)); |
| if (!plugin.get()) { |
| NOTREACHED(); |
| return NPERR_INVALID_INSTANCE_ERROR; |
| } |
| 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<PluginInstance> plugin(FindInstance(id)); |
| if (!plugin.get()) { |
| NOTREACHED(); |
| return NPERR_INVALID_INSTANCE_ERROR; |
| } |
| 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<PluginInstance> plugin = FindInstance(id); |
| if (!plugin.get()) { |
| NOTREACHED(); |
| return NPERR_INVALID_INSTANCE_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; |
| } |
| 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<PluginInstance> plugin(FindInstance(id)); |
| if (!plugin.get()) { |
| NOTREACHED(); |
| return NPERR_INVALID_INSTANCE_ERROR; |
| } |
| *private_mode = plugin->webplugin()->IsOffTheRecord(); |
| rv = NPERR_NO_ERROR; |
| break; |
| } |
| #if defined(OS_MACOSX) |
| case NPNVpluginDrawingModel: { |
| // return the drawing model that was negotiated when we initialized. |
| scoped_refptr<PluginInstance> plugin(FindInstance(id)); |
| if (!plugin.get()) { |
| NOTREACHED(); |
| return NPERR_INVALID_INSTANCE_ERROR; |
| } |
| *reinterpret_cast<int*>(value) = plugin->drawing_model(); |
| rv = NPERR_NO_ERROR; |
| break; |
| } |
| case NPNVsupportsCoreGraphicsBool: |
| case NPNVsupportsCocoaBool: { |
| // These drawing and event models are always supported. |
| NPBool* supports_model = reinterpret_cast<NPBool*>(value); |
| *supports_model = true; |
| rv = NPERR_NO_ERROR; |
| break; |
| } |
| case NPNVsupportsInvalidatingCoreAnimationBool: |
| case NPNVsupportsCoreAnimationBool: { |
| NPBool* supports_model = reinterpret_cast<NPBool*>(value); |
| *supports_model = content::SupportsCoreAnimationPlugins(); |
| rv = NPERR_NO_ERROR; |
| break; |
| } |
| #ifndef NP_NO_CARBON |
| case NPNVsupportsCarbonBool: |
| #endif |
| #ifndef NP_NO_QUICKDRAW |
| case NPNVsupportsQuickDrawBool: |
| #endif |
| case NPNVsupportsOpenGLBool: { |
| // These models are never supported. OpenGL was never widely supported, |
| // and QuickDraw and Carbon have been deprecated for quite some time. |
| NPBool* supports_model = reinterpret_cast<NPBool*>(value); |
| *supports_model = false; |
| rv = NPERR_NO_ERROR; |
| break; |
| } |
| case NPNVsupportsCompositingCoreAnimationPluginsBool: { |
| NPBool* supports_compositing = reinterpret_cast<NPBool*>(value); |
| *supports_compositing = content::SupportsCoreAnimationPlugins(); |
| rv = NPERR_NO_ERROR; |
| break; |
| } |
| case NPNVsupportsUpdatedCocoaTextInputBool: { |
| // We support the clarifications to the Cocoa IME event spec. |
| NPBool* supports_update = reinterpret_cast<NPBool*>(value); |
| *supports_update = true; |
| rv = NPERR_NO_ERROR; |
| break; |
| } |
| #endif // OS_MACOSX |
| default: |
| DVLOG(1) << "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<PluginInstance> plugin(FindInstance(id)); |
| if (!plugin.get()) { |
| NOTREACHED(); |
| return NPERR_INVALID_INSTANCE_ERROR; |
| } |
| 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 |
| DVLOG(1) << "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 |
| DVLOG(1) << "NPN_SetValue(NPPVpluginKeepLibraryInMemory) is not " |
| "implemented."; |
| return NPERR_GENERIC_ERROR; |
| #if defined(OS_MACOSX) |
| case NPPVpluginDrawingModel: { |
| intptr_t model = reinterpret_cast<intptr_t>(value); |
| if (model == NPDrawingModelCoreGraphics || |
| ((model == NPDrawingModelInvalidatingCoreAnimation || |
| model == NPDrawingModelCoreAnimation) && |
| content::SupportsCoreAnimationPlugins())) { |
| plugin->set_drawing_model(static_cast<NPDrawingModel>(model)); |
| return NPERR_NO_ERROR; |
| } |
| return NPERR_GENERIC_ERROR; |
| } |
| case NPPVpluginEventModel: { |
| // Only the Cocoa event model is supported. |
| intptr_t model = reinterpret_cast<intptr_t>(value); |
| if (model == NPEventModelCocoa) { |
| plugin->set_event_model(static_cast<NPEventModel>(model)); |
| return NPERR_NO_ERROR; |
| } |
| return NPERR_GENERIC_ERROR; |
| } |
| #endif |
| default: |
| // TODO: implement me |
| DVLOG(1) << "NPN_SetValue(" << variable << ") is not implemented."; |
| break; |
| } |
| |
| NOTREACHED(); |
| return NPERR_GENERIC_ERROR; |
| } |
| |
| void* NPN_GetJavaEnv() { |
| // TODO: implement me |
| DVLOG(1) << "NPN_GetJavaEnv is not implemented."; |
| return NULL; |
| } |
| |
| void* NPN_GetJavaPeer(NPP) { |
| // TODO: implement me |
| DVLOG(1) << "NPN_GetJavaPeer is not implemented."; |
| return NULL; |
| } |
| |
| void NPN_PushPopupsEnabledState(NPP id, NPBool enabled) { |
| scoped_refptr<PluginInstance> plugin(FindInstance(id)); |
| if (plugin.get()) |
| plugin->PushPopupsEnabledState(enabled ? true : false); |
| } |
| |
| void NPN_PopPopupsEnabledState(NPP id) { |
| scoped_refptr<PluginInstance> plugin(FindInstance(id)); |
| if (plugin.get()) |
| plugin->PopPopupsEnabledState(); |
| } |
| |
| void NPN_PluginThreadAsyncCall(NPP id, |
| void (*func)(void*), |
| void* user_data) { |
| scoped_refptr<PluginInstance> plugin(FindInstance(id)); |
| if (plugin.get()) |
| 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"; |
| scoped_refptr<PluginInstance> plugin(FindInstance(id)); |
| if (!plugin.get()) |
| return NPERR_GENERIC_ERROR; |
| |
| WebPlugin* webplugin = plugin->webplugin(); |
| if (!webplugin) |
| return NPERR_GENERIC_ERROR; |
| |
| if (!webplugin->FindProxyForUrl(GURL(std::string(url)), &result)) |
| return NPERR_GENERIC_ERROR; |
| break; |
| } |
| case NPNURLVCookie: { |
| scoped_refptr<PluginInstance> plugin(FindInstance(id)); |
| if (!plugin.get()) |
| return NPERR_GENERIC_ERROR; |
| |
| 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<PluginInstance> plugin(FindInstance(id)); |
| if (!plugin.get()) |
| return NPERR_GENERIC_ERROR; |
| |
| 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<PluginInstance> plugin(FindInstance(id)); |
| if (!plugin.get()) |
| return 0; |
| |
| return plugin->ScheduleTimer(interval, repeat, func); |
| } |
| |
| void NPN_UnscheduleTimer(NPP id, uint32_t timer_id) { |
| scoped_refptr<PluginInstance> plugin(FindInstance(id)); |
| if (plugin.get()) |
| plugin->UnscheduleTimer(timer_id); |
| } |
| |
| NPError NPN_PopUpContextMenu(NPP id, NPMenu* menu) { |
| if (!menu) |
| return NPERR_INVALID_PARAM; |
| |
| scoped_refptr<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<PluginInstance> plugin(FindInstance(id)); |
| if (plugin.get()) { |
| return plugin->ConvertPoint( |
| sourceX, sourceY, sourceSpace, destX, destY, destSpace); |
| } |
| NOTREACHED(); |
| return false; |
| } |
| |
| NPBool NPN_HandleEvent(NPP id, void *event, NPBool handled) { |
| // TODO: Implement advanced key handling: http://crbug.com/46578 |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| NPBool NPN_UnfocusInstance(NPP id, NPFocusDirection direction) { |
| // TODO: Implement advanced key handling: http://crbug.com/46578 |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void NPN_URLRedirectResponse(NPP instance, void* notify_data, NPBool allow) { |
| } |
| |
| } // extern "C" |