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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdio.h>
6 #include <string.h>
7
8 #include <string>
9 #include <vector>
10
11 #include "base/at_exit.h"
12 #include "base/basictypes.h"
13 #include "base/command_line.h"
14 #include "base/logging.h"
15 #include "base/strings/stringize_macros.h"
16 #include "net/socket/ssl_server_socket.h"
17 #include "remoting/base/plugin_thread_task_runner.h"
18 #include "remoting/base/resources.h"
19 #include "remoting/base/string_resources.h"
20 #include "remoting/host/plugin/host_log_handler.h"
21 #include "remoting/host/plugin/host_plugin_utils.h"
22 #include "remoting/host/plugin/host_script_object.h"
23 #if defined(OS_WIN)
24 #include "ui/gfx/win/dpi.h"
25 #endif
26 #include "third_party/npapi/bindings/npapi.h"
27 #include "third_party/npapi/bindings/npfunctions.h"
28 #include "third_party/npapi/bindings/npruntime.h"
29 #include "ui/base/l10n/l10n_util.h"
30
31 // Symbol export is handled with a separate def file on Windows.
32 #if defined (__GNUC__) && __GNUC__ >= 4
33 #define EXPORT __attribute__((visibility("default")))
34 #else
35 #define EXPORT
36 #endif
37
38 #if defined(OS_WIN)
39 // TODO(wez): libvpx expects these 64-bit division functions to be provided
40 // by libgcc.a, which we aren't linked against. These implementations can
41 // be removed once we have native MSVC libvpx builds for Windows.
42 extern "C" {
43
44 int64_t __cdecl __divdi3(int64_t a, int64_t b) {
45 return a / b;
46 }
47 uint64_t __cdecl __udivdi3(uint64_t a, uint64_t b) {
48 return a / b;
49 }
50
51 }
52 #endif
53
54 using remoting::g_npnetscape_funcs;
55 using remoting::HostLogHandler;
56 using remoting::HostNPScriptObject;
57 using remoting::StringFromNPIdentifier;
58
59 namespace {
60
61 bool g_initialized = false;
62
63 base::AtExitManager* g_at_exit_manager = NULL;
64
65 // The plugin name and description returned by GetValue().
66 std::string* g_ui_name = NULL;
67 std::string* g_ui_description = NULL;
68
69 // NPAPI plugin implementation for remoting host.
70 // Documentation for most of the calls in this class can be found here:
71 // https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Scripting_plugins
72 class HostNPPlugin : public remoting::PluginThreadTaskRunner::Delegate {
73 public:
74 // |mode| is the display mode of plug-in. Values:
75 // NP_EMBED: (1) Instance was created by an EMBED tag and shares the browser
76 // window with other content.
77 // NP_FULL: (2) Instance was created by a separate file and is the primary
78 // content in the window.
79 HostNPPlugin(NPP instance, uint16 mode)
80 : instance_(instance),
81 scriptable_object_(NULL) {
82 plugin_task_runner_ = new remoting::PluginThreadTaskRunner(this);
83 plugin_auto_task_runner_ =
84 new remoting::AutoThreadTaskRunner(
85 plugin_task_runner_,
86 base::Bind(&remoting::PluginThreadTaskRunner::Quit,
87 plugin_task_runner_));
88 }
89
90 virtual ~HostNPPlugin() {
91 if (scriptable_object_) {
92 DCHECK_EQ(scriptable_object_->referenceCount, 1UL);
93 g_npnetscape_funcs->releaseobject(scriptable_object_);
94 scriptable_object_ = NULL;
95 }
96
97 // Process tasks on |plugin_task_runner_| until all references to
98 // |plugin_auto_task_runner_| have been dropped. This requires that the
99 // browser has dropped any script object references - see above.
100 plugin_auto_task_runner_ = NULL;
101 plugin_task_runner_->DetachAndRunShutdownLoop();
102 }
103
104 bool Init(int16 argc, char** argn, char** argv, NPSavedData* saved) {
105 #if defined(OS_MACOSX)
106 // Use the modern CoreGraphics and Cocoa models when available, since
107 // QuickDraw and Carbon are deprecated.
108 // The drawing and event models don't change anything for this plugin, since
109 // none of the functions affected by the models actually do anything.
110 // This does however keep the plugin from breaking when Chromium eventually
111 // drops support for QuickDraw and Carbon, and it also keeps the browser
112 // from sending Null Events once a second to support old Carbon based
113 // timers.
114 // Chromium should always be supporting the newer models.
115
116 // Sanity check to see if Chromium supports the CoreGraphics drawing model.
117 NPBool supports_core_graphics = false;
118 NPError err = g_npnetscape_funcs->getvalue(instance_,
119 NPNVsupportsCoreGraphicsBool,
120 &supports_core_graphics);
121 if (err == NPERR_NO_ERROR && supports_core_graphics) {
122 // Switch to CoreGraphics drawing model.
123 g_npnetscape_funcs->setvalue(instance_, NPPVpluginDrawingModel,
124 reinterpret_cast<void*>(NPDrawingModelCoreGraphics));
125 } else {
126 LOG(ERROR) << "No Core Graphics support";
127 return false;
128 }
129
130 // Sanity check to see if Chromium supports the Cocoa event model.
131 NPBool supports_cocoa = false;
132 err = g_npnetscape_funcs->getvalue(instance_, NPNVsupportsCocoaBool,
133 &supports_cocoa);
134 if (err == NPERR_NO_ERROR && supports_cocoa) {
135 // Switch to Cocoa event model.
136 g_npnetscape_funcs->setvalue(instance_, NPPVpluginEventModel,
137 reinterpret_cast<void*>(NPEventModelCocoa));
138 } else {
139 LOG(ERROR) << "No Cocoa Event Model support";
140 return false;
141 }
142 #endif // OS_MACOSX
143 net::EnableSSLServerSockets();
144 return true;
145 }
146
147 bool Save(NPSavedData** saved) {
148 return true;
149 }
150
151 NPObject* GetScriptableObject() {
152 if (!scriptable_object_) {
153 // Must be static. If it is a temporary, objects created by this
154 // method will fail in weird and wonderful ways later.
155 static NPClass npc_ref_object = {
156 NP_CLASS_STRUCT_VERSION,
157 &Allocate,
158 &Deallocate,
159 &Invalidate,
160 &HasMethod,
161 &Invoke,
162 &InvokeDefault,
163 &HasProperty,
164 &GetProperty,
165 &SetProperty,
166 &RemoveProperty,
167 &Enumerate,
168 NULL
169 };
170 scriptable_object_ = g_npnetscape_funcs->createobject(instance_,
171 &npc_ref_object);
172 }
173 return scriptable_object_;
174 }
175
176 // PluginThreadTaskRunner::Delegate implementation.
177 virtual bool RunOnPluginThread(
178 base::TimeDelta delay, void(function)(void*), void* data) OVERRIDE {
179 if (delay == base::TimeDelta()) {
180 g_npnetscape_funcs->pluginthreadasynccall(instance_, function, data);
181 } else {
182 base::AutoLock auto_lock(timers_lock_);
183 uint32_t timer_id = g_npnetscape_funcs->scheduletimer(
184 instance_, delay.InMilliseconds(), false, &NPDelayedTaskSpringboard);
185 DelayedTask task = {function, data};
186 timers_[timer_id] = task;
187 }
188 return true;
189 }
190
191 void SetWindow(NPWindow* np_window) {
192 if (scriptable_object_) {
193 ScriptableFromObject(scriptable_object_)->SetWindow(np_window);
194 }
195 }
196
197 static void NPDelayedTaskSpringboard(NPP npp, uint32_t timer_id) {
198 HostNPPlugin* self = reinterpret_cast<HostNPPlugin*>(npp->pdata);
199 DelayedTask task;
200 {
201 base::AutoLock auto_lock(self->timers_lock_);
202 std::map<uint32_t, DelayedTask>::iterator it =
203 self->timers_.find(timer_id);
204 CHECK(it != self->timers_.end());
205 task = it->second;
206 self->timers_.erase(it);
207 }
208 task.function(task.data);
209 }
210
211 private:
212 struct ScriptableNPObject : public NPObject {
213 HostNPScriptObject* scriptable_object;
214 };
215
216 struct DelayedTask {
217 void (*function)(void*);
218 void* data;
219 };
220
221 static HostNPScriptObject* ScriptableFromObject(NPObject* obj) {
222 return reinterpret_cast<ScriptableNPObject*>(obj)->scriptable_object;
223 }
224
225 static NPObject* Allocate(NPP npp, NPClass* aClass) {
226 VLOG(2) << "static Allocate";
227 ScriptableNPObject* object =
228 reinterpret_cast<ScriptableNPObject*>(
229 g_npnetscape_funcs->memalloc(sizeof(ScriptableNPObject)));
230 HostNPPlugin* plugin = reinterpret_cast<HostNPPlugin*>(npp->pdata);
231
232 object->_class = aClass;
233 object->referenceCount = 1;
234 object->scriptable_object =
235 new HostNPScriptObject(npp, object, plugin->plugin_auto_task_runner_);
236 return object;
237 }
238
239 static void Deallocate(NPObject* npobj) {
240 VLOG(2) << "static Deallocate";
241 if (npobj) {
242 Invalidate(npobj);
243 g_npnetscape_funcs->memfree(npobj);
244 }
245 }
246
247 static void Invalidate(NPObject* npobj) {
248 if (npobj) {
249 ScriptableNPObject* object = reinterpret_cast<ScriptableNPObject*>(npobj);
250 if (object->scriptable_object) {
251 delete object->scriptable_object;
252 object->scriptable_object = NULL;
253 }
254 }
255 }
256
257 static bool HasMethod(NPObject* obj, NPIdentifier method_name) {
258 VLOG(2) << "static HasMethod";
259 HostNPScriptObject* scriptable = ScriptableFromObject(obj);
260 if (!scriptable) return false;
261 std::string method_name_string = StringFromNPIdentifier(method_name);
262 if (method_name_string.empty())
263 return false;
264 return scriptable->HasMethod(method_name_string);
265 }
266
267 static bool InvokeDefault(NPObject* obj,
268 const NPVariant* args,
269 uint32_t argCount,
270 NPVariant* result) {
271 VLOG(2) << "static InvokeDefault";
272 HostNPScriptObject* scriptable = ScriptableFromObject(obj);
273 if (!scriptable) return false;
274 return scriptable->InvokeDefault(args, argCount, result);
275 }
276
277 static bool Invoke(NPObject* obj,
278 NPIdentifier method_name,
279 const NPVariant* args,
280 uint32_t argCount,
281 NPVariant* result) {
282 VLOG(2) << "static Invoke";
283 HostNPScriptObject* scriptable = ScriptableFromObject(obj);
284 if (!scriptable)
285 return false;
286 std::string method_name_string = StringFromNPIdentifier(method_name);
287 if (method_name_string.empty())
288 return false;
289 return scriptable->Invoke(method_name_string, args, argCount, result);
290 }
291
292 static bool HasProperty(NPObject* obj, NPIdentifier property_name) {
293 VLOG(2) << "static HasProperty";
294 HostNPScriptObject* scriptable = ScriptableFromObject(obj);
295 if (!scriptable) return false;
296 std::string property_name_string = StringFromNPIdentifier(property_name);
297 if (property_name_string.empty())
298 return false;
299 return scriptable->HasProperty(property_name_string);
300 }
301
302 static bool GetProperty(NPObject* obj,
303 NPIdentifier property_name,
304 NPVariant* result) {
305 VLOG(2) << "static GetProperty";
306 HostNPScriptObject* scriptable = ScriptableFromObject(obj);
307 if (!scriptable) return false;
308 std::string property_name_string = StringFromNPIdentifier(property_name);
309 if (property_name_string.empty())
310 return false;
311 return scriptable->GetProperty(property_name_string, result);
312 }
313
314 static bool SetProperty(NPObject* obj,
315 NPIdentifier property_name,
316 const NPVariant* value) {
317 VLOG(2) << "static SetProperty";
318 HostNPScriptObject* scriptable = ScriptableFromObject(obj);
319 if (!scriptable) return false;
320 std::string property_name_string = StringFromNPIdentifier(property_name);
321 if (property_name_string.empty())
322 return false;
323 return scriptable->SetProperty(property_name_string, value);
324 }
325
326 static bool RemoveProperty(NPObject* obj, NPIdentifier property_name) {
327 VLOG(2) << "static RemoveProperty";
328 HostNPScriptObject* scriptable = ScriptableFromObject(obj);
329 if (!scriptable) return false;
330 std::string property_name_string = StringFromNPIdentifier(property_name);
331 if (property_name_string.empty())
332 return false;
333 return scriptable->RemoveProperty(property_name_string);
334 }
335
336 static bool Enumerate(NPObject* obj,
337 NPIdentifier** value,
338 uint32_t* count) {
339 VLOG(2) << "static Enumerate";
340 HostNPScriptObject* scriptable = ScriptableFromObject(obj);
341 if (!scriptable) return false;
342 std::vector<std::string> values;
343 bool is_good = scriptable->Enumerate(&values);
344 if (is_good) {
345 *count = values.size();
346 *value = reinterpret_cast<NPIdentifier*>(
347 g_npnetscape_funcs->memalloc(sizeof(NPIdentifier) * (*count)));
348 for (uint32_t i = 0; i < *count; ++i) {
349 (*value)[i] =
350 g_npnetscape_funcs->getstringidentifier(values[i].c_str());
351 }
352 }
353 return is_good;
354 }
355
356 NPP instance_;
357 NPObject* scriptable_object_;
358
359 scoped_refptr<remoting::PluginThreadTaskRunner> plugin_task_runner_;
360 scoped_refptr<remoting::AutoThreadTaskRunner> plugin_auto_task_runner_;
361
362 std::map<uint32_t, DelayedTask> timers_;
363 base::Lock timers_lock_;
364 };
365
366 void InitializePlugin() {
367 if (g_initialized)
368 return;
369
370 g_initialized = true;
371 g_at_exit_manager = new base::AtExitManager;
372
373 // Init an empty command line for common objects that use it.
374 base::CommandLine::Init(0, NULL);
375
376 if (remoting::LoadResources("")) {
377 g_ui_name = new std::string(
378 l10n_util::GetStringUTF8(IDS_REMOTING_HOST_PLUGIN_NAME));
379 g_ui_description = new std::string(
380 l10n_util::GetStringUTF8(IDS_REMOTING_HOST_PLUGIN_DESCRIPTION));
381 } else {
382 g_ui_name = new std::string();
383 g_ui_description = new std::string();
384 }
385 }
386
387 void ShutdownPlugin() {
388 delete g_ui_name;
389 delete g_ui_description;
390
391 remoting::UnloadResources();
392
393 delete g_at_exit_manager;
394 }
395
396 // Utility functions to map NPAPI Entry Points to C++ Objects.
397 HostNPPlugin* PluginFromInstance(NPP instance) {
398 return reinterpret_cast<HostNPPlugin*>(instance->pdata);
399 }
400
401 NPError CreatePlugin(NPMIMEType pluginType,
402 NPP instance,
403 uint16 mode,
404 int16 argc,
405 char** argn,
406 char** argv,
407 NPSavedData* saved) {
408 VLOG(2) << "CreatePlugin";
409
410 // Register a global log handler.
411 // The LogMessage registration code is not thread-safe, so we need to perform
412 // this while we're running in a single thread.
413 HostLogHandler::RegisterLogMessageHandler();
414
415 HostNPPlugin* plugin = new HostNPPlugin(instance, mode);
416 instance->pdata = plugin;
417 if (!plugin->Init(argc, argn, argv, saved)) {
418 delete plugin;
419 instance->pdata = NULL;
420 return NPERR_INVALID_PLUGIN_ERROR;
421 } else {
422 return NPERR_NO_ERROR;
423 }
424 }
425
426 NPError DestroyPlugin(NPP instance,
427 NPSavedData** save) {
428 VLOG(2) << "DestroyPlugin";
429
430 // Normally, we would unregister the global log handler that we registered
431 // in CreatePlugin. However, the LogHandler registration code is not thread-
432 // safe so we could crash if we update (register or unregister) the
433 // LogHandler while it's being read on another thread.
434 // At this point, all our threads should be shutdown, but it's safer to leave
435 // the handler registered until we're completely destroyed.
436
437 HostNPPlugin* plugin = PluginFromInstance(instance);
438 if (plugin) {
439 plugin->Save(save);
440 delete plugin;
441 instance->pdata = NULL;
442 return NPERR_NO_ERROR;
443 } else {
444 return NPERR_INVALID_PLUGIN_ERROR;
445 }
446 }
447
448 NPError GetValue(NPP instance, NPPVariable variable, void* value) {
449 // NP_GetValue() can be called before NP_Initialize().
450 InitializePlugin();
451
452 switch (variable) {
453 default:
454 VLOG(2) << "GetValue - default " << variable;
455 return NPERR_GENERIC_ERROR;
456 case NPPVpluginNameString:
457 VLOG(2) << "GetValue - name string";
458 *reinterpret_cast<const char**>(value) = g_ui_name->c_str();
459 break;
460 case NPPVpluginDescriptionString:
461 VLOG(2) << "GetValue - description string";
462 *reinterpret_cast<const char**>(value) = g_ui_description->c_str();
463 break;
464 case NPPVpluginNeedsXEmbed:
465 VLOG(2) << "GetValue - NeedsXEmbed";
466 *(static_cast<NPBool*>(value)) = true;
467 break;
468 case NPPVpluginScriptableNPObject:
469 VLOG(2) << "GetValue - scriptable object";
470 HostNPPlugin* plugin = PluginFromInstance(instance);
471 if (!plugin)
472 return NPERR_INVALID_PLUGIN_ERROR;
473 NPObject* scriptable_object = plugin->GetScriptableObject();
474 g_npnetscape_funcs->retainobject(scriptable_object);
475 *reinterpret_cast<NPObject**>(value) = scriptable_object;
476 break;
477 }
478 return NPERR_NO_ERROR;
479 }
480
481 NPError HandleEvent(NPP instance, void* ev) {
482 VLOG(2) << "HandleEvent";
483 return NPERR_NO_ERROR;
484 }
485
486 NPError SetWindow(NPP instance, NPWindow* pNPWindow) {
487 VLOG(2) << "SetWindow";
488 HostNPPlugin* plugin = PluginFromInstance(instance);
489 if (plugin) {
490 plugin->SetWindow(pNPWindow);
491 }
492 return NPERR_NO_ERROR;
493 }
494
495 } // namespace
496
497 #if defined(OS_WIN)
498 BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) {
499 switch (dwReason) {
500 case DLL_PROCESS_ATTACH:
501 DisableThreadLibraryCalls(hModule);
502 break;
503 case DLL_PROCESS_DETACH:
504 case DLL_THREAD_ATTACH:
505 case DLL_THREAD_DETACH:
506 break;
507 }
508 return TRUE;
509 }
510 #endif
511
512 // The actual required NPAPI Entry points
513
514 extern "C" {
515
516 EXPORT NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* nppfuncs) {
517 VLOG(2) << "NP_GetEntryPoints";
518 nppfuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
519 nppfuncs->newp = &CreatePlugin;
520 nppfuncs->destroy = &DestroyPlugin;
521 nppfuncs->getvalue = &GetValue;
522 nppfuncs->event = &HandleEvent;
523 nppfuncs->setwindow = &SetWindow;
524
525 return NPERR_NO_ERROR;
526 }
527
528 EXPORT NPError API_CALL NP_Initialize(NPNetscapeFuncs* npnetscape_funcs
529 #if defined(OS_POSIX) && !defined(OS_MACOSX)
530 , NPPluginFuncs* nppfuncs
531 #endif
532 ) {
533 VLOG(2) << "NP_Initialize";
534 InitializePlugin();
535
536 if (npnetscape_funcs == NULL)
537 return NPERR_INVALID_FUNCTABLE_ERROR;
538
539 if (((npnetscape_funcs->version & 0xff00) >> 8) > NP_VERSION_MAJOR)
540 return NPERR_INCOMPATIBLE_VERSION_ERROR;
541
542 g_npnetscape_funcs = npnetscape_funcs;
543 #if defined(OS_POSIX) && !defined(OS_MACOSX)
544 NP_GetEntryPoints(nppfuncs);
545 #endif
546
547 #if defined(OS_WIN)
548 gfx::EnableHighDPISupport();
549 #endif
550
551 return NPERR_NO_ERROR;
552 }
553
554 EXPORT NPError API_CALL NP_Shutdown() {
555 VLOG(2) << "NP_Shutdown";
556 ShutdownPlugin();
557
558 return NPERR_NO_ERROR;
559 }
560
561 #if defined(OS_POSIX) && !defined(OS_MACOSX)
562 EXPORT const char* API_CALL NP_GetMIMEDescription(void) {
563 VLOG(2) << "NP_GetMIMEDescription";
564 return STRINGIZE(HOST_PLUGIN_MIME_TYPE) "::";
565 }
566
567 EXPORT NPError API_CALL NP_GetValue(void* npp,
568 NPPVariable variable,
569 void* value) {
570 return GetValue((NPP)npp, variable, value);
571 }
572 #endif
573
574 } // extern "C"
OLDNEW
« 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