Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Unified Diff: remoting/host/plugin/host_plugin.cc

Issue 340993002: Revert of Remove NPAPI plugin from chromoting webapp. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « remoting/host/plugin/host_log_handler.cc ('k') | remoting/host/plugin/host_plugin.def » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/host/plugin/host_plugin.cc
diff --git a/remoting/host/plugin/host_plugin.cc b/remoting/host/plugin/host_plugin.cc
new file mode 100644
index 0000000000000000000000000000000000000000..213ea89d78b3e7f29f181f78f5adb1413e0c991b
--- /dev/null
+++ b/remoting/host/plugin/host_plugin.cc
@@ -0,0 +1,574 @@
+// 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 <stdio.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+#include "base/at_exit.h"
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/stringize_macros.h"
+#include "net/socket/ssl_server_socket.h"
+#include "remoting/base/plugin_thread_task_runner.h"
+#include "remoting/base/resources.h"
+#include "remoting/base/string_resources.h"
+#include "remoting/host/plugin/host_log_handler.h"
+#include "remoting/host/plugin/host_plugin_utils.h"
+#include "remoting/host/plugin/host_script_object.h"
+#if defined(OS_WIN)
+#include "ui/gfx/win/dpi.h"
+#endif
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npfunctions.h"
+#include "third_party/npapi/bindings/npruntime.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// Symbol export is handled with a separate def file on Windows.
+#if defined (__GNUC__) && __GNUC__ >= 4
+#define EXPORT __attribute__((visibility("default")))
+#else
+#define EXPORT
+#endif
+
+#if defined(OS_WIN)
+// TODO(wez): libvpx expects these 64-bit division functions to be provided
+// by libgcc.a, which we aren't linked against. These implementations can
+// be removed once we have native MSVC libvpx builds for Windows.
+extern "C" {
+
+int64_t __cdecl __divdi3(int64_t a, int64_t b) {
+ return a / b;
+}
+uint64_t __cdecl __udivdi3(uint64_t a, uint64_t b) {
+ return a / b;
+}
+
+}
+#endif
+
+using remoting::g_npnetscape_funcs;
+using remoting::HostLogHandler;
+using remoting::HostNPScriptObject;
+using remoting::StringFromNPIdentifier;
+
+namespace {
+
+bool g_initialized = false;
+
+base::AtExitManager* g_at_exit_manager = NULL;
+
+// The plugin name and description returned by GetValue().
+std::string* g_ui_name = NULL;
+std::string* g_ui_description = NULL;
+
+// NPAPI plugin implementation for remoting host.
+// Documentation for most of the calls in this class can be found here:
+// https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Scripting_plugins
+class HostNPPlugin : public remoting::PluginThreadTaskRunner::Delegate {
+ public:
+ // |mode| is the display mode of plug-in. Values:
+ // NP_EMBED: (1) Instance was created by an EMBED tag and shares the browser
+ // window with other content.
+ // NP_FULL: (2) Instance was created by a separate file and is the primary
+ // content in the window.
+ HostNPPlugin(NPP instance, uint16 mode)
+ : instance_(instance),
+ scriptable_object_(NULL) {
+ plugin_task_runner_ = new remoting::PluginThreadTaskRunner(this);
+ plugin_auto_task_runner_ =
+ new remoting::AutoThreadTaskRunner(
+ plugin_task_runner_,
+ base::Bind(&remoting::PluginThreadTaskRunner::Quit,
+ plugin_task_runner_));
+ }
+
+ virtual ~HostNPPlugin() {
+ if (scriptable_object_) {
+ DCHECK_EQ(scriptable_object_->referenceCount, 1UL);
+ g_npnetscape_funcs->releaseobject(scriptable_object_);
+ scriptable_object_ = NULL;
+ }
+
+ // Process tasks on |plugin_task_runner_| until all references to
+ // |plugin_auto_task_runner_| have been dropped. This requires that the
+ // browser has dropped any script object references - see above.
+ plugin_auto_task_runner_ = NULL;
+ plugin_task_runner_->DetachAndRunShutdownLoop();
+ }
+
+ bool Init(int16 argc, char** argn, char** argv, NPSavedData* saved) {
+#if defined(OS_MACOSX)
+ // Use the modern CoreGraphics and Cocoa models when available, since
+ // QuickDraw and Carbon are deprecated.
+ // The drawing and event models don't change anything for this plugin, since
+ // none of the functions affected by the models actually do anything.
+ // This does however keep the plugin from breaking when Chromium eventually
+ // drops support for QuickDraw and Carbon, and it also keeps the browser
+ // from sending Null Events once a second to support old Carbon based
+ // timers.
+ // Chromium should always be supporting the newer models.
+
+ // Sanity check to see if Chromium supports the CoreGraphics drawing model.
+ NPBool supports_core_graphics = false;
+ NPError err = g_npnetscape_funcs->getvalue(instance_,
+ NPNVsupportsCoreGraphicsBool,
+ &supports_core_graphics);
+ if (err == NPERR_NO_ERROR && supports_core_graphics) {
+ // Switch to CoreGraphics drawing model.
+ g_npnetscape_funcs->setvalue(instance_, NPPVpluginDrawingModel,
+ reinterpret_cast<void*>(NPDrawingModelCoreGraphics));
+ } else {
+ LOG(ERROR) << "No Core Graphics support";
+ return false;
+ }
+
+ // Sanity check to see if Chromium supports the Cocoa event model.
+ NPBool supports_cocoa = false;
+ err = g_npnetscape_funcs->getvalue(instance_, NPNVsupportsCocoaBool,
+ &supports_cocoa);
+ if (err == NPERR_NO_ERROR && supports_cocoa) {
+ // Switch to Cocoa event model.
+ g_npnetscape_funcs->setvalue(instance_, NPPVpluginEventModel,
+ reinterpret_cast<void*>(NPEventModelCocoa));
+ } else {
+ LOG(ERROR) << "No Cocoa Event Model support";
+ return false;
+ }
+#endif // OS_MACOSX
+ net::EnableSSLServerSockets();
+ return true;
+ }
+
+ bool Save(NPSavedData** saved) {
+ return true;
+ }
+
+ NPObject* GetScriptableObject() {
+ if (!scriptable_object_) {
+ // Must be static. If it is a temporary, objects created by this
+ // method will fail in weird and wonderful ways later.
+ static NPClass npc_ref_object = {
+ NP_CLASS_STRUCT_VERSION,
+ &Allocate,
+ &Deallocate,
+ &Invalidate,
+ &HasMethod,
+ &Invoke,
+ &InvokeDefault,
+ &HasProperty,
+ &GetProperty,
+ &SetProperty,
+ &RemoveProperty,
+ &Enumerate,
+ NULL
+ };
+ scriptable_object_ = g_npnetscape_funcs->createobject(instance_,
+ &npc_ref_object);
+ }
+ return scriptable_object_;
+ }
+
+ // PluginThreadTaskRunner::Delegate implementation.
+ virtual bool RunOnPluginThread(
+ base::TimeDelta delay, void(function)(void*), void* data) OVERRIDE {
+ if (delay == base::TimeDelta()) {
+ g_npnetscape_funcs->pluginthreadasynccall(instance_, function, data);
+ } else {
+ base::AutoLock auto_lock(timers_lock_);
+ uint32_t timer_id = g_npnetscape_funcs->scheduletimer(
+ instance_, delay.InMilliseconds(), false, &NPDelayedTaskSpringboard);
+ DelayedTask task = {function, data};
+ timers_[timer_id] = task;
+ }
+ return true;
+ }
+
+ void SetWindow(NPWindow* np_window) {
+ if (scriptable_object_) {
+ ScriptableFromObject(scriptable_object_)->SetWindow(np_window);
+ }
+ }
+
+ static void NPDelayedTaskSpringboard(NPP npp, uint32_t timer_id) {
+ HostNPPlugin* self = reinterpret_cast<HostNPPlugin*>(npp->pdata);
+ DelayedTask task;
+ {
+ base::AutoLock auto_lock(self->timers_lock_);
+ std::map<uint32_t, DelayedTask>::iterator it =
+ self->timers_.find(timer_id);
+ CHECK(it != self->timers_.end());
+ task = it->second;
+ self->timers_.erase(it);
+ }
+ task.function(task.data);
+ }
+
+ private:
+ struct ScriptableNPObject : public NPObject {
+ HostNPScriptObject* scriptable_object;
+ };
+
+ struct DelayedTask {
+ void (*function)(void*);
+ void* data;
+ };
+
+ static HostNPScriptObject* ScriptableFromObject(NPObject* obj) {
+ return reinterpret_cast<ScriptableNPObject*>(obj)->scriptable_object;
+ }
+
+ static NPObject* Allocate(NPP npp, NPClass* aClass) {
+ VLOG(2) << "static Allocate";
+ ScriptableNPObject* object =
+ reinterpret_cast<ScriptableNPObject*>(
+ g_npnetscape_funcs->memalloc(sizeof(ScriptableNPObject)));
+ HostNPPlugin* plugin = reinterpret_cast<HostNPPlugin*>(npp->pdata);
+
+ object->_class = aClass;
+ object->referenceCount = 1;
+ object->scriptable_object =
+ new HostNPScriptObject(npp, object, plugin->plugin_auto_task_runner_);
+ return object;
+ }
+
+ static void Deallocate(NPObject* npobj) {
+ VLOG(2) << "static Deallocate";
+ if (npobj) {
+ Invalidate(npobj);
+ g_npnetscape_funcs->memfree(npobj);
+ }
+ }
+
+ static void Invalidate(NPObject* npobj) {
+ if (npobj) {
+ ScriptableNPObject* object = reinterpret_cast<ScriptableNPObject*>(npobj);
+ if (object->scriptable_object) {
+ delete object->scriptable_object;
+ object->scriptable_object = NULL;
+ }
+ }
+ }
+
+ static bool HasMethod(NPObject* obj, NPIdentifier method_name) {
+ VLOG(2) << "static HasMethod";
+ HostNPScriptObject* scriptable = ScriptableFromObject(obj);
+ if (!scriptable) return false;
+ std::string method_name_string = StringFromNPIdentifier(method_name);
+ if (method_name_string.empty())
+ return false;
+ return scriptable->HasMethod(method_name_string);
+ }
+
+ static bool InvokeDefault(NPObject* obj,
+ const NPVariant* args,
+ uint32_t argCount,
+ NPVariant* result) {
+ VLOG(2) << "static InvokeDefault";
+ HostNPScriptObject* scriptable = ScriptableFromObject(obj);
+ if (!scriptable) return false;
+ return scriptable->InvokeDefault(args, argCount, result);
+ }
+
+ static bool Invoke(NPObject* obj,
+ NPIdentifier method_name,
+ const NPVariant* args,
+ uint32_t argCount,
+ NPVariant* result) {
+ VLOG(2) << "static Invoke";
+ HostNPScriptObject* scriptable = ScriptableFromObject(obj);
+ if (!scriptable)
+ return false;
+ std::string method_name_string = StringFromNPIdentifier(method_name);
+ if (method_name_string.empty())
+ return false;
+ return scriptable->Invoke(method_name_string, args, argCount, result);
+ }
+
+ static bool HasProperty(NPObject* obj, NPIdentifier property_name) {
+ VLOG(2) << "static HasProperty";
+ HostNPScriptObject* scriptable = ScriptableFromObject(obj);
+ if (!scriptable) return false;
+ std::string property_name_string = StringFromNPIdentifier(property_name);
+ if (property_name_string.empty())
+ return false;
+ return scriptable->HasProperty(property_name_string);
+ }
+
+ static bool GetProperty(NPObject* obj,
+ NPIdentifier property_name,
+ NPVariant* result) {
+ VLOG(2) << "static GetProperty";
+ HostNPScriptObject* scriptable = ScriptableFromObject(obj);
+ if (!scriptable) return false;
+ std::string property_name_string = StringFromNPIdentifier(property_name);
+ if (property_name_string.empty())
+ return false;
+ return scriptable->GetProperty(property_name_string, result);
+ }
+
+ static bool SetProperty(NPObject* obj,
+ NPIdentifier property_name,
+ const NPVariant* value) {
+ VLOG(2) << "static SetProperty";
+ HostNPScriptObject* scriptable = ScriptableFromObject(obj);
+ if (!scriptable) return false;
+ std::string property_name_string = StringFromNPIdentifier(property_name);
+ if (property_name_string.empty())
+ return false;
+ return scriptable->SetProperty(property_name_string, value);
+ }
+
+ static bool RemoveProperty(NPObject* obj, NPIdentifier property_name) {
+ VLOG(2) << "static RemoveProperty";
+ HostNPScriptObject* scriptable = ScriptableFromObject(obj);
+ if (!scriptable) return false;
+ std::string property_name_string = StringFromNPIdentifier(property_name);
+ if (property_name_string.empty())
+ return false;
+ return scriptable->RemoveProperty(property_name_string);
+ }
+
+ static bool Enumerate(NPObject* obj,
+ NPIdentifier** value,
+ uint32_t* count) {
+ VLOG(2) << "static Enumerate";
+ HostNPScriptObject* scriptable = ScriptableFromObject(obj);
+ if (!scriptable) return false;
+ std::vector<std::string> values;
+ bool is_good = scriptable->Enumerate(&values);
+ if (is_good) {
+ *count = values.size();
+ *value = reinterpret_cast<NPIdentifier*>(
+ g_npnetscape_funcs->memalloc(sizeof(NPIdentifier) * (*count)));
+ for (uint32_t i = 0; i < *count; ++i) {
+ (*value)[i] =
+ g_npnetscape_funcs->getstringidentifier(values[i].c_str());
+ }
+ }
+ return is_good;
+ }
+
+ NPP instance_;
+ NPObject* scriptable_object_;
+
+ scoped_refptr<remoting::PluginThreadTaskRunner> plugin_task_runner_;
+ scoped_refptr<remoting::AutoThreadTaskRunner> plugin_auto_task_runner_;
+
+ std::map<uint32_t, DelayedTask> timers_;
+ base::Lock timers_lock_;
+};
+
+void InitializePlugin() {
+ if (g_initialized)
+ return;
+
+ g_initialized = true;
+ g_at_exit_manager = new base::AtExitManager;
+
+ // Init an empty command line for common objects that use it.
+ base::CommandLine::Init(0, NULL);
+
+ if (remoting::LoadResources("")) {
+ g_ui_name = new std::string(
+ l10n_util::GetStringUTF8(IDS_REMOTING_HOST_PLUGIN_NAME));
+ g_ui_description = new std::string(
+ l10n_util::GetStringUTF8(IDS_REMOTING_HOST_PLUGIN_DESCRIPTION));
+ } else {
+ g_ui_name = new std::string();
+ g_ui_description = new std::string();
+ }
+}
+
+void ShutdownPlugin() {
+ delete g_ui_name;
+ delete g_ui_description;
+
+ remoting::UnloadResources();
+
+ delete g_at_exit_manager;
+}
+
+// Utility functions to map NPAPI Entry Points to C++ Objects.
+HostNPPlugin* PluginFromInstance(NPP instance) {
+ return reinterpret_cast<HostNPPlugin*>(instance->pdata);
+}
+
+NPError CreatePlugin(NPMIMEType pluginType,
+ NPP instance,
+ uint16 mode,
+ int16 argc,
+ char** argn,
+ char** argv,
+ NPSavedData* saved) {
+ VLOG(2) << "CreatePlugin";
+
+ // Register a global log handler.
+ // The LogMessage registration code is not thread-safe, so we need to perform
+ // this while we're running in a single thread.
+ HostLogHandler::RegisterLogMessageHandler();
+
+ HostNPPlugin* plugin = new HostNPPlugin(instance, mode);
+ instance->pdata = plugin;
+ if (!plugin->Init(argc, argn, argv, saved)) {
+ delete plugin;
+ instance->pdata = NULL;
+ return NPERR_INVALID_PLUGIN_ERROR;
+ } else {
+ return NPERR_NO_ERROR;
+ }
+}
+
+NPError DestroyPlugin(NPP instance,
+ NPSavedData** save) {
+ VLOG(2) << "DestroyPlugin";
+
+ // Normally, we would unregister the global log handler that we registered
+ // in CreatePlugin. However, the LogHandler registration code is not thread-
+ // safe so we could crash if we update (register or unregister) the
+ // LogHandler while it's being read on another thread.
+ // At this point, all our threads should be shutdown, but it's safer to leave
+ // the handler registered until we're completely destroyed.
+
+ HostNPPlugin* plugin = PluginFromInstance(instance);
+ if (plugin) {
+ plugin->Save(save);
+ delete plugin;
+ instance->pdata = NULL;
+ return NPERR_NO_ERROR;
+ } else {
+ return NPERR_INVALID_PLUGIN_ERROR;
+ }
+}
+
+NPError GetValue(NPP instance, NPPVariable variable, void* value) {
+ // NP_GetValue() can be called before NP_Initialize().
+ InitializePlugin();
+
+ switch (variable) {
+ default:
+ VLOG(2) << "GetValue - default " << variable;
+ return NPERR_GENERIC_ERROR;
+ case NPPVpluginNameString:
+ VLOG(2) << "GetValue - name string";
+ *reinterpret_cast<const char**>(value) = g_ui_name->c_str();
+ break;
+ case NPPVpluginDescriptionString:
+ VLOG(2) << "GetValue - description string";
+ *reinterpret_cast<const char**>(value) = g_ui_description->c_str();
+ break;
+ case NPPVpluginNeedsXEmbed:
+ VLOG(2) << "GetValue - NeedsXEmbed";
+ *(static_cast<NPBool*>(value)) = true;
+ break;
+ case NPPVpluginScriptableNPObject:
+ VLOG(2) << "GetValue - scriptable object";
+ HostNPPlugin* plugin = PluginFromInstance(instance);
+ if (!plugin)
+ return NPERR_INVALID_PLUGIN_ERROR;
+ NPObject* scriptable_object = plugin->GetScriptableObject();
+ g_npnetscape_funcs->retainobject(scriptable_object);
+ *reinterpret_cast<NPObject**>(value) = scriptable_object;
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError HandleEvent(NPP instance, void* ev) {
+ VLOG(2) << "HandleEvent";
+ return NPERR_NO_ERROR;
+}
+
+NPError SetWindow(NPP instance, NPWindow* pNPWindow) {
+ VLOG(2) << "SetWindow";
+ HostNPPlugin* plugin = PluginFromInstance(instance);
+ if (plugin) {
+ plugin->SetWindow(pNPWindow);
+ }
+ return NPERR_NO_ERROR;
+}
+
+} // namespace
+
+#if defined(OS_WIN)
+BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) {
+ switch (dwReason) {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hModule);
+ break;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+// The actual required NPAPI Entry points
+
+extern "C" {
+
+EXPORT NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* nppfuncs) {
+ VLOG(2) << "NP_GetEntryPoints";
+ nppfuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+ nppfuncs->newp = &CreatePlugin;
+ nppfuncs->destroy = &DestroyPlugin;
+ nppfuncs->getvalue = &GetValue;
+ nppfuncs->event = &HandleEvent;
+ nppfuncs->setwindow = &SetWindow;
+
+ return NPERR_NO_ERROR;
+}
+
+EXPORT NPError API_CALL NP_Initialize(NPNetscapeFuncs* npnetscape_funcs
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ , NPPluginFuncs* nppfuncs
+#endif
+ ) {
+ VLOG(2) << "NP_Initialize";
+ InitializePlugin();
+
+ if (npnetscape_funcs == NULL)
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ if (((npnetscape_funcs->version & 0xff00) >> 8) > NP_VERSION_MAJOR)
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+
+ g_npnetscape_funcs = npnetscape_funcs;
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ NP_GetEntryPoints(nppfuncs);
+#endif
+
+#if defined(OS_WIN)
+ gfx::EnableHighDPISupport();
+#endif
+
+ return NPERR_NO_ERROR;
+}
+
+EXPORT NPError API_CALL NP_Shutdown() {
+ VLOG(2) << "NP_Shutdown";
+ ShutdownPlugin();
+
+ return NPERR_NO_ERROR;
+}
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+EXPORT const char* API_CALL NP_GetMIMEDescription(void) {
+ VLOG(2) << "NP_GetMIMEDescription";
+ return STRINGIZE(HOST_PLUGIN_MIME_TYPE) "::";
+}
+
+EXPORT NPError API_CALL NP_GetValue(void* npp,
+ NPPVariable variable,
+ void* value) {
+ return GetValue((NPP)npp, variable, value);
+}
+#endif
+
+} // extern "C"
« no previous file with comments | « remoting/host/plugin/host_log_handler.cc ('k') | remoting/host/plugin/host_plugin.def » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698