Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / child / npapi / plugin_host.cc
blobe9cdb4adef123ee3ccd96ddb601bccc2151f47b9
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.
5 #include "content/child/npapi/plugin_host.h"
7 #include "base/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "build/build_config.h"
17 #include "content/child/npapi/plugin_instance.h"
18 #include "content/child/npapi/plugin_lib.h"
19 #include "content/child/npapi/plugin_stream_url.h"
20 #include "content/child/npapi/webplugin_delegate.h"
21 #include "content/public/common/content_client.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/user_agent.h"
24 #include "content/public/common/webplugininfo.h"
25 #include "net/base/filename_util.h"
26 #include "third_party/WebKit/public/web/WebBindings.h"
27 #include "third_party/WebKit/public/web/WebKit.h"
28 #include "third_party/npapi/bindings/npruntime.h"
29 #include "ui/gl/gl_implementation.h"
30 #include "ui/gl/gl_surface.h"
32 using blink::WebBindings;
34 // Declarations for stub implementations of deprecated functions, which are no
35 // longer listed in npapi.h.
36 extern "C" {
37 void* NPN_GetJavaEnv();
38 void* NPN_GetJavaPeer(NPP);
41 namespace content {
43 // Finds a PluginInstance from an NPP.
44 // The caller must take a reference if needed.
45 static PluginInstance* FindInstance(NPP id) {
46 if (id == NULL) {
47 return NULL;
49 return reinterpret_cast<PluginInstance*>(id->ndata);
52 #if defined(OS_MACOSX)
53 // Returns true if Core Animation plugins are supported. This requires that the
54 // OS supports shared accelerated surfaces via IOSurface. This is true on Snow
55 // Leopard and higher.
56 static bool SupportsCoreAnimationPlugins() {
57 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
58 switches::kDisableCoreAnimationPlugins))
59 return false;
60 // We also need to be running with desktop GL and not the software
61 // OSMesa renderer in order to share accelerated surfaces between
62 // processes. Because on MacOS we lazy-initialize GLSurface in the
63 // renderer process here, ensure we're not also initializing GL somewhere
64 // else, and that we only do this once.
65 static gfx::GLImplementation implementation = gfx::kGLImplementationNone;
66 if (implementation == gfx::kGLImplementationNone) {
67 // Not initialized yet.
68 DCHECK_EQ(implementation, gfx::GetGLImplementation())
69 << "GL already initialized by someone else to: "
70 << gfx::GetGLImplementation();
71 if (!gfx::GLSurface::InitializeOneOff()) {
72 return false;
74 implementation = gfx::GetGLImplementation();
76 return (implementation == gfx::kGLImplementationDesktopGL);
78 #endif
80 PluginHost::PluginHost() {
81 InitializeHostFuncs();
84 PluginHost::~PluginHost() {
87 PluginHost *PluginHost::Singleton() {
88 CR_DEFINE_STATIC_LOCAL(scoped_refptr<PluginHost>, singleton, ());
89 if (singleton.get() == NULL) {
90 singleton = new PluginHost();
93 DCHECK(singleton.get() != NULL);
94 return singleton.get();
97 void PluginHost::InitializeHostFuncs() {
98 memset(&host_funcs_, 0, sizeof(host_funcs_));
99 host_funcs_.size = sizeof(host_funcs_);
100 host_funcs_.version = (NP_VERSION_MAJOR << 8) | (NP_VERSION_MINOR);
102 // The "basic" functions
103 host_funcs_.geturl = &NPN_GetURL;
104 host_funcs_.posturl = &NPN_PostURL;
105 host_funcs_.requestread = &NPN_RequestRead;
106 host_funcs_.newstream = &NPN_NewStream;
107 host_funcs_.write = &NPN_Write;
108 host_funcs_.destroystream = &NPN_DestroyStream;
109 host_funcs_.status = &NPN_Status;
110 host_funcs_.uagent = &NPN_UserAgent;
111 host_funcs_.memalloc = &NPN_MemAlloc;
112 host_funcs_.memfree = &NPN_MemFree;
113 host_funcs_.memflush = &NPN_MemFlush;
114 host_funcs_.reloadplugins = &NPN_ReloadPlugins;
116 // Stubs for deprecated Java functions
117 host_funcs_.getJavaEnv = &NPN_GetJavaEnv;
118 host_funcs_.getJavaPeer = &NPN_GetJavaPeer;
120 // Advanced functions we implement
121 host_funcs_.geturlnotify = &NPN_GetURLNotify;
122 host_funcs_.posturlnotify = &NPN_PostURLNotify;
123 host_funcs_.getvalue = &NPN_GetValue;
124 host_funcs_.setvalue = &NPN_SetValue;
125 host_funcs_.invalidaterect = &NPN_InvalidateRect;
126 host_funcs_.invalidateregion = &NPN_InvalidateRegion;
127 host_funcs_.forceredraw = &NPN_ForceRedraw;
129 // These come from the Javascript Engine
130 host_funcs_.getstringidentifier = WebBindings::getStringIdentifier;
131 host_funcs_.getstringidentifiers = WebBindings::getStringIdentifiers;
132 host_funcs_.getintidentifier = WebBindings::getIntIdentifier;
133 host_funcs_.identifierisstring = WebBindings::identifierIsString;
134 host_funcs_.utf8fromidentifier = WebBindings::utf8FromIdentifier;
135 host_funcs_.intfromidentifier = WebBindings::intFromIdentifier;
136 host_funcs_.createobject = WebBindings::createObject;
137 host_funcs_.retainobject = WebBindings::retainObject;
138 host_funcs_.releaseobject = WebBindings::releaseObject;
139 host_funcs_.invoke = WebBindings::invoke;
140 host_funcs_.invokeDefault = WebBindings::invokeDefault;
141 host_funcs_.evaluate = WebBindings::evaluate;
142 host_funcs_.getproperty = WebBindings::getProperty;
143 host_funcs_.setproperty = WebBindings::setProperty;
144 host_funcs_.removeproperty = WebBindings::removeProperty;
145 host_funcs_.hasproperty = WebBindings::hasProperty;
146 host_funcs_.hasmethod = WebBindings::hasMethod;
147 host_funcs_.releasevariantvalue = WebBindings::releaseVariantValue;
148 host_funcs_.setexception = WebBindings::setException;
149 host_funcs_.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
150 host_funcs_.poppopupsenabledstate = NPN_PopPopupsEnabledState;
151 host_funcs_.enumerate = WebBindings::enumerate;
152 host_funcs_.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
153 host_funcs_.construct = WebBindings::construct;
154 host_funcs_.getvalueforurl = NPN_GetValueForURL;
155 host_funcs_.setvalueforurl = NPN_SetValueForURL;
156 host_funcs_.getauthenticationinfo = NPN_GetAuthenticationInfo;
157 host_funcs_.scheduletimer = NPN_ScheduleTimer;
158 host_funcs_.unscheduletimer = NPN_UnscheduleTimer;
159 host_funcs_.popupcontextmenu = NPN_PopUpContextMenu;
160 host_funcs_.convertpoint = NPN_ConvertPoint;
161 host_funcs_.handleevent = NPN_HandleEvent;
162 host_funcs_.unfocusinstance = NPN_UnfocusInstance;
163 host_funcs_.urlredirectresponse = NPN_URLRedirectResponse;
166 void PluginHost::PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides) {
167 // When running in the plugin process, we need to patch the NPN functions
168 // that the plugin calls to interact with NPObjects that we give. Otherwise
169 // the plugin will call the v8 NPN functions, which won't work since we have
170 // an NPObjectProxy and not a real v8 implementation.
171 if (overrides->invoke)
172 host_funcs_.invoke = overrides->invoke;
174 if (overrides->invokeDefault)
175 host_funcs_.invokeDefault = overrides->invokeDefault;
177 if (overrides->evaluate)
178 host_funcs_.evaluate = overrides->evaluate;
180 if (overrides->getproperty)
181 host_funcs_.getproperty = overrides->getproperty;
183 if (overrides->setproperty)
184 host_funcs_.setproperty = overrides->setproperty;
186 if (overrides->removeproperty)
187 host_funcs_.removeproperty = overrides->removeproperty;
189 if (overrides->hasproperty)
190 host_funcs_.hasproperty = overrides->hasproperty;
192 if (overrides->hasmethod)
193 host_funcs_.hasmethod = overrides->hasmethod;
195 if (overrides->setexception)
196 host_funcs_.setexception = overrides->setexception;
198 if (overrides->enumerate)
199 host_funcs_.enumerate = overrides->enumerate;
202 bool PluginHost::SetPostData(const char* buf,
203 uint32 length,
204 std::vector<std::string>* names,
205 std::vector<std::string>* values,
206 std::vector<char>* body) {
207 // Use a state table to do the parsing. Whitespace must be
208 // trimmed after the fact if desired. In our case, we actually
209 // don't care about the whitespace, because we're just going to
210 // pass this back into another POST. This function strips out the
211 // "Content-length" header and does not append it to the request.
214 // This parser takes action only on state changes.
216 // Transition table:
217 // : \n NULL Other
218 // 0 GetHeader 1 2 4 0
219 // 1 GetValue 1 0 3 1
220 // 2 GetData 2 2 3 2
221 // 3 DONE
222 // 4 ERR
224 enum { INPUT_COLON=0, INPUT_NEWLINE, INPUT_NULL, INPUT_OTHER };
225 enum { GETNAME, GETVALUE, GETDATA, DONE, ERR };
226 int statemachine[3][4] = { { GETVALUE, GETDATA, GETDATA, GETNAME },
227 { GETVALUE, GETNAME, DONE, GETVALUE },
228 { GETDATA, GETDATA, DONE, GETDATA } };
229 std::string name, value;
230 const char* ptr = static_cast<const char*>(buf);
231 const char* start = ptr;
232 int state = GETNAME; // initial state
233 bool done = false;
234 bool err = false;
235 do {
236 int input;
238 // Translate the current character into an input
239 // for the state table.
240 switch (*ptr) {
241 case ':' :
242 input = INPUT_COLON;
243 break;
244 case '\n':
245 input = INPUT_NEWLINE;
246 break;
247 case 0 :
248 input = INPUT_NULL;
249 break;
250 default :
251 input = INPUT_OTHER;
252 break;
255 int newstate = statemachine[state][input];
257 // Take action based on the new state.
258 if (state != newstate) {
259 switch (newstate) {
260 case GETNAME:
261 // Got a value.
262 value = std::string(start, ptr - start);
263 base::TrimWhitespace(value, base::TRIM_ALL, &value);
264 // If the name field is empty, we'll skip this header
265 // but we won't error out.
266 if (!name.empty() && name != "content-length") {
267 names->push_back(name);
268 values->push_back(value);
270 start = ptr + 1;
271 break;
272 case GETVALUE:
273 // Got a header.
274 name = base::StringToLowerASCII(std::string(start, ptr - start));
275 base::TrimWhitespace(name, base::TRIM_ALL, &name);
276 start = ptr + 1;
277 break;
278 case GETDATA: {
279 // Finished headers, now get body
280 if (*ptr)
281 start = ptr + 1;
282 size_t previous_size = body->size();
283 size_t new_body_size = length - static_cast<int>(start - buf);
284 body->resize(previous_size + new_body_size);
285 if (!body->empty())
286 memcpy(&body->front() + previous_size, start, new_body_size);
287 done = true;
288 break;
290 case ERR:
291 // error
292 err = true;
293 done = true;
294 break;
297 state = newstate;
298 ptr++;
299 } while (!done);
301 return !err;
304 } // namespace content
306 extern "C" {
308 using content::FindInstance;
309 using content::PluginHost;
310 using content::PluginInstance;
311 using content::WebPlugin;
313 // Allocates memory from the host's memory space.
314 void* NPN_MemAlloc(uint32_t size) {
315 // Note: We must use the same allocator/deallocator
316 // that is used by the javascript library, as some of the
317 // JS APIs will pass memory to the plugin which the plugin
318 // will attempt to free.
319 return malloc(size);
322 // Deallocates memory from the host's memory space
323 void NPN_MemFree(void* ptr) {
324 if (ptr != NULL && ptr != reinterpret_cast<void*>(-1))
325 free(ptr);
328 // Requests that the host free a specified amount of memory.
329 uint32_t NPN_MemFlush(uint32_t size) {
330 // This is not relevant on Windows; MAC specific
331 return size;
334 // This is for dynamic discovery of new plugins.
335 // Should force a re-scan of the plugins directory to load new ones.
336 void NPN_ReloadPlugins(NPBool reload_pages) {
337 blink::resetPluginCache(reload_pages ? true : false);
340 // Requests a range of bytes for a seekable stream.
341 NPError NPN_RequestRead(NPStream* stream, NPByteRange* range_list) {
342 if (!stream || !range_list)
343 return NPERR_GENERIC_ERROR;
345 scoped_refptr<PluginInstance> plugin(
346 reinterpret_cast<PluginInstance*>(stream->ndata));
347 if (!plugin.get())
348 return NPERR_GENERIC_ERROR;
350 plugin->RequestRead(stream, range_list);
351 return NPERR_NO_ERROR;
354 // Generic form of GetURL for common code between GetURL and GetURLNotify.
355 static NPError GetURLNotify(NPP id,
356 const char* url,
357 const char* target,
358 bool notify,
359 void* notify_data) {
360 if (!url)
361 return NPERR_INVALID_URL;
363 scoped_refptr<PluginInstance> plugin(FindInstance(id));
364 if (!plugin.get()) {
365 return NPERR_GENERIC_ERROR;
368 plugin->RequestURL(url, "GET", target, NULL, 0, notify, notify_data);
369 return NPERR_NO_ERROR;
372 // Requests creation of a new stream with the contents of the
373 // specified URL; gets notification of the result.
374 NPError NPN_GetURLNotify(NPP id,
375 const char* url,
376 const char* target,
377 void* notify_data) {
378 // This is identical to NPN_GetURL, but after finishing, the
379 // browser will call NPP_URLNotify to inform the plugin that
380 // it has completed.
382 // According to the NPAPI documentation, if target == _self
383 // or a parent to _self, the browser should return NPERR_INVALID_PARAM,
384 // because it can't notify the plugin once deleted. This is
385 // absolutely false; firefox doesn't do this, and Flash relies on
386 // being able to use this.
388 // Also according to the NPAPI documentation, we should return
389 // NPERR_INVALID_URL if the url requested is not valid. However,
390 // this would require that we synchronously start fetching the
391 // URL. That just isn't practical. As such, there really is
392 // no way to return this error. From looking at the Firefox
393 // implementation, it doesn't look like Firefox does this either.
395 return GetURLNotify(id, url, target, true, notify_data);
398 NPError NPN_GetURL(NPP id, const char* url, const char* target) {
399 // Notes:
400 // Request from the Plugin to fetch content either for the plugin
401 // or to be placed into a browser window.
403 // If target == null, the browser fetches content and streams to plugin.
404 // otherwise, the browser loads content into an existing browser frame.
405 // If the target is the window/frame containing the plugin, the plugin
406 // may be destroyed.
407 // If the target is _blank, a mailto: or news: url open content in a new
408 // browser window
409 // If the target is _self, no other instance of the plugin is created. The
410 // plugin continues to operate in its own window
412 return GetURLNotify(id, url, target, false, 0);
415 // Generic form of PostURL for common code between PostURL and PostURLNotify.
416 static NPError PostURLNotify(NPP id,
417 const char* url,
418 const char* target,
419 uint32_t len,
420 const char* buf,
421 NPBool file,
422 bool notify,
423 void* notify_data) {
424 if (!url)
425 return NPERR_INVALID_URL;
427 scoped_refptr<PluginInstance> plugin(FindInstance(id));
428 if (!plugin.get()) {
429 NOTREACHED();
430 return NPERR_GENERIC_ERROR;
433 std::string post_file_contents;
435 if (file) {
436 // Post data to be uploaded from a file. This can be handled in two
437 // ways.
438 // 1. Read entire file and send the contents as if it was a post data
439 // specified in the argument
440 // 2. Send just the file details and read them in the browser at the
441 // time of sending the request.
442 // Approach 2 is more efficient but complicated. Approach 1 has a major
443 // drawback of sending potentially large data over two IPC hops. In a way
444 // 'large data over IPC' problem exists as it is in case of plugin giving
445 // the data directly instead of in a file.
446 // Currently we are going with the approach 1 to get the feature working.
447 // We can optimize this later with approach 2.
449 // TODO(joshia): Design a scheme to send a file descriptor instead of
450 // entire file contents across.
452 // Security alert:
453 // ---------------
454 // Here we are blindly uploading whatever file requested by a plugin.
455 // This is risky as someone could exploit a plugin to send private
456 // data in arbitrary locations.
457 // A malicious (non-sandboxed) plugin has unfeterred access to OS
458 // resources and can do this anyway without using browser's HTTP stack.
459 // FWIW, Firefox and Safari don't perform any security checks.
461 if (!buf)
462 return NPERR_FILE_NOT_FOUND;
464 std::string file_path_ascii(buf);
465 base::FilePath file_path;
466 static const char kFileUrlPrefix[] = "file:";
467 if (base::StartsWith(file_path_ascii, kFileUrlPrefix,
468 base::CompareCase::INSENSITIVE_ASCII)) {
469 GURL file_url(file_path_ascii);
470 DCHECK(file_url.SchemeIsFile());
471 net::FileURLToFilePath(file_url, &file_path);
472 } else {
473 file_path = base::FilePath::FromUTF8Unsafe(file_path_ascii);
476 base::File::Info post_file_info;
477 if (!base::GetFileInfo(file_path, &post_file_info) ||
478 post_file_info.is_directory)
479 return NPERR_FILE_NOT_FOUND;
481 if (!base::ReadFileToString(file_path, &post_file_contents))
482 return NPERR_FILE_NOT_FOUND;
484 buf = post_file_contents.c_str();
485 len = post_file_contents.size();
488 // The post data sent by a plugin contains both headers
489 // and post data. Example:
490 // Content-type: text/html
491 // Content-length: 200
493 // <200 bytes of content here>
495 // Unfortunately, our stream needs these broken apart,
496 // so we need to parse the data and set headers and data
497 // separately.
498 plugin->RequestURL(url, "POST", target, buf, len, notify, notify_data);
499 return NPERR_NO_ERROR;
502 NPError NPN_PostURLNotify(NPP id,
503 const char* url,
504 const char* target,
505 uint32_t len,
506 const char* buf,
507 NPBool file,
508 void* notify_data) {
509 return PostURLNotify(id, url, target, len, buf, file, true, notify_data);
512 NPError NPN_PostURL(NPP id,
513 const char* url,
514 const char* target,
515 uint32_t len,
516 const char* buf,
517 NPBool file) {
518 // POSTs data to an URL, either from a temp file or a buffer.
519 // If file is true, buf contains a temp file (which host will delete after
520 // completing), and len contains the length of the filename.
521 // If file is false, buf contains the data to send, and len contains the
522 // length of the buffer
524 // If target is null,
525 // server response is returned to the plugin
526 // If target is _current, _self, or _top,
527 // server response is written to the plugin window and plugin is unloaded.
528 // If target is _new or _blank,
529 // server response is written to a new browser window
530 // If target is an existing frame,
531 // server response goes to that frame.
533 // For protocols other than FTP
534 // file uploads must be line-end converted from \r\n to \n
536 // Note: you cannot specify headers (even a blank line) in a memory buffer,
537 // use NPN_PostURLNotify
539 return PostURLNotify(id, url, target, len, buf, file, false, 0);
542 NPError NPN_NewStream(NPP id,
543 NPMIMEType type,
544 const char* target,
545 NPStream** stream) {
546 // Requests creation of a new data stream produced by the plugin,
547 // consumed by the browser.
549 // Browser should put this stream into a window target.
551 // TODO: implement me
552 DVLOG(1) << "NPN_NewStream is not implemented yet.";
553 return NPERR_GENERIC_ERROR;
556 int32_t NPN_Write(NPP id, NPStream* stream, int32_t len, void* buffer) {
557 // Writes data to an existing Plugin-created stream.
559 // TODO: implement me
560 DVLOG(1) << "NPN_Write is not implemented yet.";
561 return NPERR_GENERIC_ERROR;
564 NPError NPN_DestroyStream(NPP id, NPStream* stream, NPReason reason) {
565 // Destroys a stream (could be created by plugin or browser).
567 // Reasons:
568 // NPRES_DONE - normal completion
569 // NPRES_USER_BREAK - user terminated
570 // NPRES_NETWORK_ERROR - network error (all errors fit here?)
574 scoped_refptr<PluginInstance> plugin(FindInstance(id));
575 if (plugin.get() == NULL) {
576 NOTREACHED();
577 return NPERR_GENERIC_ERROR;
580 return plugin->NPP_DestroyStream(stream, reason);
583 const char* NPN_UserAgent(NPP id) {
584 #if defined(OS_WIN)
585 // Flash passes in a null id during the NP_initialize call. We need to
586 // default to the Mozilla user agent if we don't have an NPP instance or
587 // else Flash won't request windowless mode.
588 bool use_mozilla_user_agent = true;
589 if (id) {
590 scoped_refptr<PluginInstance> plugin = FindInstance(id);
591 if (plugin.get() && !plugin->use_mozilla_user_agent())
592 use_mozilla_user_agent = false;
595 if (use_mozilla_user_agent)
596 return "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) "
597 "Gecko/20061103 Firefox/2.0a1";
598 #endif
600 // Provide a consistent user-agent string with memory that lasts
601 // long enough for the caller to read it.
602 static base::LazyInstance<std::string>::Leaky leaky_user_agent =
603 LAZY_INSTANCE_INITIALIZER;
604 if (leaky_user_agent == NULL)
605 leaky_user_agent.Get() = content::GetContentClient()->GetUserAgent();
606 return leaky_user_agent.Get().c_str();
609 void NPN_Status(NPP id, const char* message) {
610 // Displays a message on the status line of the browser window.
612 // TODO: implement me
613 DVLOG(1) << "NPN_Status is not implemented yet.";
616 void NPN_InvalidateRect(NPP id, NPRect *invalidRect) {
617 // Invalidates specified drawing area prior to repainting or refreshing a
618 // windowless plugin
620 // Before a windowless plugin can refresh part of its drawing area, it must
621 // first invalidate it. This function causes the NPP_HandleEvent method to
622 // pass an update event or a paint message to the plugin. After calling
623 // this method, the plugin receives a paint message asynchronously.
625 // The browser redraws invalid areas of the document and any windowless
626 // plugins at regularly timed intervals. To force a paint message, the
627 // plugin can call NPN_ForceRedraw after calling this method.
629 scoped_refptr<PluginInstance> plugin(FindInstance(id));
630 if (plugin.get() && plugin->webplugin()) {
631 if (invalidRect) {
632 #if defined(OS_WIN)
633 if (!plugin->windowless()) {
634 RECT rect = {0};
635 rect.left = invalidRect->left;
636 rect.right = invalidRect->right;
637 rect.top = invalidRect->top;
638 rect.bottom = invalidRect->bottom;
639 ::InvalidateRect(plugin->window_handle(), &rect, false);
640 return;
642 #endif
643 gfx::Rect rect(invalidRect->left,
644 invalidRect->top,
645 invalidRect->right - invalidRect->left,
646 invalidRect->bottom - invalidRect->top);
647 plugin->webplugin()->InvalidateRect(rect);
648 } else {
649 plugin->webplugin()->Invalidate();
654 void NPN_InvalidateRegion(NPP id, NPRegion invalidRegion) {
655 // Invalidates a specified drawing region prior to repainting
656 // or refreshing a window-less plugin.
658 // Similar to NPN_InvalidateRect.
660 // TODO: this is overkill--add platform-specific region handling (at the
661 // very least, fetch the region's bounding box and pass it to InvalidateRect).
662 scoped_refptr<PluginInstance> plugin(FindInstance(id));
663 DCHECK(plugin.get() != NULL);
664 if (plugin.get() && plugin->webplugin())
665 plugin->webplugin()->Invalidate();
668 void NPN_ForceRedraw(NPP id) {
669 // Forces repaint for a windowless plugin.
671 // We deliberately do not implement this; we don't want plugins forcing
672 // synchronous paints.
675 NPError NPN_GetValue(NPP id, NPNVariable variable, void* value) {
676 // Allows the plugin to query the browser for information
678 // Variables:
679 // NPNVxDisplay (unix only)
680 // NPNVxtAppContext (unix only)
681 // NPNVnetscapeWindow (win only) - Gets the native window on which the
682 // plugin drawing occurs, returns HWND
683 // NPNVjavascriptEnabledBool: tells whether Javascript is enabled
684 // NPNVasdEnabledBool: tells whether SmartUpdate is enabled
685 // NPNVOfflineBool: tells whether offline-mode is enabled
687 NPError rv = NPERR_GENERIC_ERROR;
689 switch (static_cast<int>(variable)) {
690 case NPNVWindowNPObject: {
691 scoped_refptr<PluginInstance> plugin(FindInstance(id));
692 if (!plugin.get()) {
693 NOTREACHED();
694 return NPERR_INVALID_INSTANCE_ERROR;
696 NPObject *np_object = plugin->webplugin()->GetWindowScriptNPObject();
697 // Return value is expected to be retained, as
698 // described here:
699 // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
700 if (np_object) {
701 WebBindings::retainObject(np_object);
702 void **v = (void **)value;
703 *v = np_object;
704 rv = NPERR_NO_ERROR;
705 } else {
706 NOTREACHED();
708 break;
710 case NPNVPluginElementNPObject: {
711 scoped_refptr<PluginInstance> plugin(FindInstance(id));
712 if (!plugin.get()) {
713 NOTREACHED();
714 return NPERR_INVALID_INSTANCE_ERROR;
716 NPObject *np_object = plugin->webplugin()->GetPluginElement();
717 // Return value is expected to be retained, as
718 // described here:
719 // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
720 if (np_object) {
721 WebBindings::retainObject(np_object);
722 void** v = static_cast<void**>(value);
723 *v = np_object;
724 rv = NPERR_NO_ERROR;
725 } else {
726 NOTREACHED();
728 break;
730 #if !defined(OS_MACOSX) // OS X doesn't have windowed plugins.
731 case NPNVnetscapeWindow: {
732 scoped_refptr<PluginInstance> plugin = FindInstance(id);
733 if (!plugin.get()) {
734 NOTREACHED();
735 return NPERR_INVALID_INSTANCE_ERROR;
737 gfx::PluginWindowHandle handle = plugin->window_handle();
738 *((void**)value) = (void*)handle;
739 rv = NPERR_NO_ERROR;
740 break;
742 #endif
743 case NPNVjavascriptEnabledBool: {
744 // yes, JS is enabled.
745 *((void**)value) = (void*)1;
746 rv = NPERR_NO_ERROR;
747 break;
749 case NPNVSupportsWindowless: {
750 NPBool* supports_windowless = reinterpret_cast<NPBool*>(value);
751 *supports_windowless = true;
752 rv = NPERR_NO_ERROR;
753 break;
755 case NPNVprivateModeBool: {
756 NPBool* private_mode = reinterpret_cast<NPBool*>(value);
757 scoped_refptr<PluginInstance> plugin(FindInstance(id));
758 if (!plugin.get()) {
759 NOTREACHED();
760 return NPERR_INVALID_INSTANCE_ERROR;
762 *private_mode = plugin->webplugin()->IsOffTheRecord();
763 rv = NPERR_NO_ERROR;
764 break;
766 #if defined(OS_MACOSX)
767 case NPNVpluginDrawingModel: {
768 // return the drawing model that was negotiated when we initialized.
769 scoped_refptr<PluginInstance> plugin(FindInstance(id));
770 if (!plugin.get()) {
771 NOTREACHED();
772 return NPERR_INVALID_INSTANCE_ERROR;
774 *reinterpret_cast<int*>(value) = plugin->drawing_model();
775 rv = NPERR_NO_ERROR;
776 break;
778 case NPNVsupportsCoreGraphicsBool:
779 case NPNVsupportsCocoaBool: {
780 // These drawing and event models are always supported.
781 NPBool* supports_model = reinterpret_cast<NPBool*>(value);
782 *supports_model = true;
783 rv = NPERR_NO_ERROR;
784 break;
786 case NPNVsupportsInvalidatingCoreAnimationBool:
787 case NPNVsupportsCoreAnimationBool: {
788 NPBool* supports_model = reinterpret_cast<NPBool*>(value);
789 *supports_model = content::SupportsCoreAnimationPlugins();
790 rv = NPERR_NO_ERROR;
791 break;
793 #ifndef NP_NO_CARBON
794 case NPNVsupportsCarbonBool:
795 #endif
796 #ifndef NP_NO_QUICKDRAW
797 case NPNVsupportsQuickDrawBool:
798 #endif
799 case NPNVsupportsOpenGLBool: {
800 // These models are never supported. OpenGL was never widely supported,
801 // and QuickDraw and Carbon have been deprecated for quite some time.
802 NPBool* supports_model = reinterpret_cast<NPBool*>(value);
803 *supports_model = false;
804 rv = NPERR_NO_ERROR;
805 break;
807 case NPNVsupportsCompositingCoreAnimationPluginsBool: {
808 NPBool* supports_compositing = reinterpret_cast<NPBool*>(value);
809 *supports_compositing = content::SupportsCoreAnimationPlugins();
810 rv = NPERR_NO_ERROR;
811 break;
813 case NPNVsupportsUpdatedCocoaTextInputBool: {
814 // We support the clarifications to the Cocoa IME event spec.
815 NPBool* supports_update = reinterpret_cast<NPBool*>(value);
816 *supports_update = true;
817 rv = NPERR_NO_ERROR;
818 break;
820 #endif // OS_MACOSX
821 default:
822 DVLOG(1) << "NPN_GetValue(" << variable << ") is not implemented yet.";
823 break;
825 return rv;
828 NPError NPN_SetValue(NPP id, NPPVariable variable, void* value) {
829 // Allows the plugin to set various modes
831 scoped_refptr<PluginInstance> plugin(FindInstance(id));
832 if (!plugin.get()) {
833 NOTREACHED();
834 return NPERR_INVALID_INSTANCE_ERROR;
836 switch(variable) {
837 case NPPVpluginWindowBool: {
838 // Sets windowless mode for display of the plugin
839 // Note: the documentation at
840 // http://developer.mozilla.org/en/docs/NPN_SetValue is wrong. When
841 // value is NULL, the mode is set to true. This is the same way Mozilla
842 // works.
843 plugin->set_windowless(value == 0);
844 return NPERR_NO_ERROR;
846 case NPPVpluginTransparentBool: {
847 // Sets transparent mode for display of the plugin
849 // Transparent plugins require the browser to paint the background
850 // before having the plugin paint. By default, windowless plugins
851 // are transparent. Making a windowless plugin opaque means that
852 // the plugin does not require the browser to paint the background.
853 bool mode = (value != 0);
854 plugin->set_transparent(mode);
855 return NPERR_NO_ERROR;
857 case NPPVjavascriptPushCallerBool:
858 // Specifies whether you are pushing or popping the JSContext off.
859 // the stack
860 // TODO: implement me
861 DVLOG(1) << "NPN_SetValue(NPPVJavascriptPushCallerBool) is not "
862 "implemented.";
863 return NPERR_GENERIC_ERROR;
864 case NPPVpluginKeepLibraryInMemory:
865 // Tells browser that plugin library should live longer than usual.
866 // TODO: implement me
867 DVLOG(1) << "NPN_SetValue(NPPVpluginKeepLibraryInMemory) is not "
868 "implemented.";
869 return NPERR_GENERIC_ERROR;
870 #if defined(OS_MACOSX)
871 case NPPVpluginDrawingModel: {
872 intptr_t model = reinterpret_cast<intptr_t>(value);
873 if (model == NPDrawingModelCoreGraphics ||
874 ((model == NPDrawingModelInvalidatingCoreAnimation ||
875 model == NPDrawingModelCoreAnimation) &&
876 content::SupportsCoreAnimationPlugins())) {
877 plugin->set_drawing_model(static_cast<NPDrawingModel>(model));
878 return NPERR_NO_ERROR;
880 return NPERR_GENERIC_ERROR;
882 case NPPVpluginEventModel: {
883 // Only the Cocoa event model is supported.
884 intptr_t model = reinterpret_cast<intptr_t>(value);
885 if (model == NPEventModelCocoa) {
886 plugin->set_event_model(static_cast<NPEventModel>(model));
887 return NPERR_NO_ERROR;
889 return NPERR_GENERIC_ERROR;
891 #endif
892 default:
893 // TODO: implement me
894 DVLOG(1) << "NPN_SetValue(" << variable << ") is not implemented.";
895 break;
898 NOTREACHED();
899 return NPERR_GENERIC_ERROR;
902 void* NPN_GetJavaEnv() {
903 // TODO: implement me
904 DVLOG(1) << "NPN_GetJavaEnv is not implemented.";
905 return NULL;
908 void* NPN_GetJavaPeer(NPP) {
909 // TODO: implement me
910 DVLOG(1) << "NPN_GetJavaPeer is not implemented.";
911 return NULL;
914 void NPN_PushPopupsEnabledState(NPP id, NPBool enabled) {
915 scoped_refptr<PluginInstance> plugin(FindInstance(id));
916 if (plugin.get())
917 plugin->PushPopupsEnabledState(enabled ? true : false);
920 void NPN_PopPopupsEnabledState(NPP id) {
921 scoped_refptr<PluginInstance> plugin(FindInstance(id));
922 if (plugin.get())
923 plugin->PopPopupsEnabledState();
926 void NPN_PluginThreadAsyncCall(NPP id,
927 void (*func)(void*),
928 void* user_data) {
929 scoped_refptr<PluginInstance> plugin(FindInstance(id));
930 if (plugin.get())
931 plugin->PluginThreadAsyncCall(func, user_data);
934 NPError NPN_GetValueForURL(NPP id,
935 NPNURLVariable variable,
936 const char* url,
937 char** value,
938 uint32_t* len) {
939 if (!id)
940 return NPERR_INVALID_PARAM;
942 if (!url || !*url || !len)
943 return NPERR_INVALID_URL;
945 *len = 0;
946 std::string result;
948 switch (variable) {
949 case NPNURLVProxy: {
950 result = "DIRECT";
951 scoped_refptr<PluginInstance> plugin(FindInstance(id));
952 if (!plugin.get())
953 return NPERR_GENERIC_ERROR;
955 WebPlugin* webplugin = plugin->webplugin();
956 if (!webplugin)
957 return NPERR_GENERIC_ERROR;
959 if (!webplugin->FindProxyForUrl(GURL(std::string(url)), &result))
960 return NPERR_GENERIC_ERROR;
961 break;
963 case NPNURLVCookie: {
964 scoped_refptr<PluginInstance> plugin(FindInstance(id));
965 if (!plugin.get())
966 return NPERR_GENERIC_ERROR;
968 WebPlugin* webplugin = plugin->webplugin();
969 if (!webplugin)
970 return NPERR_GENERIC_ERROR;
972 // Bypass third-party cookie blocking by using the url as the
973 // first_party_for_cookies.
974 GURL cookies_url((std::string(url)));
975 result = webplugin->GetCookies(cookies_url, cookies_url);
976 break;
978 default:
979 return NPERR_GENERIC_ERROR;
982 // Allocate this using the NPAPI allocator. The plugin will call
983 // NPN_Free to free this.
984 *value = static_cast<char*>(NPN_MemAlloc(result.length() + 1));
985 base::strlcpy(*value, result.c_str(), result.length() + 1);
986 *len = result.length();
988 return NPERR_NO_ERROR;
991 NPError NPN_SetValueForURL(NPP id,
992 NPNURLVariable variable,
993 const char* url,
994 const char* value,
995 uint32_t len) {
996 if (!id)
997 return NPERR_INVALID_PARAM;
999 if (!url || !*url)
1000 return NPERR_INVALID_URL;
1002 switch (variable) {
1003 case NPNURLVCookie: {
1004 scoped_refptr<PluginInstance> plugin(FindInstance(id));
1005 if (!plugin.get())
1006 return NPERR_GENERIC_ERROR;
1008 WebPlugin* webplugin = plugin->webplugin();
1009 if (!webplugin)
1010 return NPERR_GENERIC_ERROR;
1012 std::string cookie(value, len);
1013 GURL cookies_url((std::string(url)));
1014 webplugin->SetCookie(cookies_url, cookies_url, cookie);
1015 return NPERR_NO_ERROR;
1017 case NPNURLVProxy:
1018 // We don't support setting proxy values, fall through...
1019 break;
1020 default:
1021 // Fall through and return an error...
1022 break;
1025 return NPERR_GENERIC_ERROR;
1028 NPError NPN_GetAuthenticationInfo(NPP id,
1029 const char* protocol,
1030 const char* host,
1031 int32_t port,
1032 const char* scheme,
1033 const char* realm,
1034 char** username,
1035 uint32_t* ulen,
1036 char** password,
1037 uint32_t* plen) {
1038 if (!id || !protocol || !host || !scheme || !realm || !username ||
1039 !ulen || !password || !plen)
1040 return NPERR_INVALID_PARAM;
1042 // TODO: implement me (bug 23928)
1043 return NPERR_GENERIC_ERROR;
1046 uint32_t NPN_ScheduleTimer(NPP id,
1047 uint32_t interval,
1048 NPBool repeat,
1049 void (*func)(NPP id, uint32_t timer_id)) {
1050 scoped_refptr<PluginInstance> plugin(FindInstance(id));
1051 if (!plugin.get())
1052 return 0;
1054 return plugin->ScheduleTimer(interval, repeat, func);
1057 void NPN_UnscheduleTimer(NPP id, uint32_t timer_id) {
1058 scoped_refptr<PluginInstance> plugin(FindInstance(id));
1059 if (plugin.get())
1060 plugin->UnscheduleTimer(timer_id);
1063 NPError NPN_PopUpContextMenu(NPP id, NPMenu* menu) {
1064 if (!menu)
1065 return NPERR_INVALID_PARAM;
1067 scoped_refptr<PluginInstance> plugin(FindInstance(id));
1068 if (plugin.get()) {
1069 return plugin->PopUpContextMenu(menu);
1071 NOTREACHED();
1072 return NPERR_GENERIC_ERROR;
1075 NPBool NPN_ConvertPoint(NPP id, double sourceX, double sourceY,
1076 NPCoordinateSpace sourceSpace,
1077 double *destX, double *destY,
1078 NPCoordinateSpace destSpace) {
1079 scoped_refptr<PluginInstance> plugin(FindInstance(id));
1080 if (plugin.get()) {
1081 return plugin->ConvertPoint(
1082 sourceX, sourceY, sourceSpace, destX, destY, destSpace);
1084 NOTREACHED();
1085 return false;
1088 NPBool NPN_HandleEvent(NPP id, void *event, NPBool handled) {
1089 // TODO: Implement advanced key handling: http://crbug.com/46578
1090 NOTIMPLEMENTED();
1091 return false;
1094 NPBool NPN_UnfocusInstance(NPP id, NPFocusDirection direction) {
1095 // TODO: Implement advanced key handling: http://crbug.com/46578
1096 NOTIMPLEMENTED();
1097 return false;
1100 void NPN_URLRedirectResponse(NPP instance, void* notify_data, NPBool allow) {
1101 scoped_refptr<PluginInstance> plugin(FindInstance(instance));
1102 if (plugin.get()) {
1103 plugin->URLRedirectResponse(!!allow, notify_data);
1107 } // extern "C"