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

Side by Side Diff: webkit/plugins/npapi/plugin_host.cc

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

Powered by Google App Engine
This is Rietveld 408576698