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

Side by Side Diff: webkit/glue/plugins/webplugin_delegate_impl_gtk.cc

Issue 19413: Linux plugins WIP. (Closed)
Patch Set: review comments Created 11 years, 10 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
« no previous file with comments | « webkit/glue/plugins/webplugin_delegate_impl.h ('k') | webkit/glue/webplugin_delegate.h » ('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) 2006-2008 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 // HACK: we need this #define in place before npapi.h is included for
6 // plugins to work. However, all sorts of headers include npapi.h, so
7 // the only way to be certain the define is in place is to put it
8 // here. You might ask, "Why not set it in npapi.h directly, or in
9 // this directory's SConscript, then?" but it turns out this define
10 // makes npapi.h include Xlib.h, which in turn defines a ton of symbols
11 // like None and Status, causing conflicts with the aforementioned
12 // many headers that include npapi.h. Ugh.
13 // See also plugin_host.cc.
14 #define MOZ_X11 1
15
16 #include "webkit/glue/plugins/webplugin_delegate_impl.h"
17
18 #include <string>
19 #include <vector>
20
21 #include <gtk/gtk.h>
22 #include <gdk/gdkx.h>
23
24 #include "base/file_util.h"
25 #include "base/message_loop.h"
26 #include "base/process_util.h"
27 #include "base/stats_counters.h"
28 #include "base/string_util.h"
29 // #include "webkit/default_plugin/plugin_impl.h"
30 #include "webkit/glue/glue_util.h"
31 #include "webkit/glue/webplugin.h"
32 #include "webkit/glue/plugins/plugin_constants_win.h"
33 #include "webkit/glue/plugins/plugin_instance.h"
34 #include "webkit/glue/plugins/plugin_lib.h"
35 #include "webkit/glue/plugins/plugin_list.h"
36 #include "webkit/glue/plugins/plugin_stream_url.h"
37 #include "webkit/glue/webkit_glue.h"
38
39 WebPluginDelegateImpl* WebPluginDelegateImpl::Create(
40 const FilePath& filename,
41 const std::string& mime_type,
42 gfx::NativeView containing_view) {
43 scoped_refptr<NPAPI::PluginLib> plugin =
44 NPAPI::PluginLib::CreatePluginLib(filename);
45 if (plugin.get() == NULL)
46 return NULL;
47
48 NPError err = plugin->NP_Initialize();
49 if (err != NPERR_NO_ERROR)
50 return NULL;
51
52 scoped_refptr<NPAPI::PluginInstance> instance =
53 plugin->CreateInstance(mime_type);
54 return new WebPluginDelegateImpl(containing_view, instance.get());
55 }
56
57 WebPluginDelegateImpl::WebPluginDelegateImpl(
58 gfx::NativeView containing_view,
59 NPAPI::PluginInstance *instance)
60 :
61 windowed_handle_(0),
62 windowless_(false),
63 plugin_(NULL),
64 instance_(instance),
65 parent_(containing_view),
66 quirks_(0)
67 {
68 memset(&window_, 0, sizeof(window_));
69
70 }
71
72 WebPluginDelegateImpl::~WebPluginDelegateImpl() {
73 DestroyInstance();
74
75 if (!windowless_)
76 WindowedDestroyWindow();
77 }
78
79 void WebPluginDelegateImpl::PluginDestroyed() {
80 delete this;
81 }
82
83 bool WebPluginDelegateImpl::Initialize(const GURL& url,
84 char** argn,
85 char** argv,
86 int argc,
87 WebPlugin* plugin,
88 bool load_manually) {
89 plugin_ = plugin;
90
91 instance_->set_web_plugin(plugin);
92 NPAPI::PluginInstance* old_instance =
93 NPAPI::PluginInstance::SetInitializingInstance(instance_);
94
95 bool start_result = instance_->Start(url, argn, argv, argc, load_manually);
96
97 NPAPI::PluginInstance::SetInitializingInstance(old_instance);
98
99 if (!start_result)
100 return false;
101
102 windowless_ = instance_->windowless();
103 if (windowless_) {
104 // For windowless plugins we should set the containing window handle
105 // as the instance window handle. This is what Safari does. Not having
106 // a valid window handle causes subtle bugs with plugins which retreive
107 // the window handle and validate the same. The window handle can be
108 // retreived via NPN_GetValue of NPNVnetscapeWindow.
109 NOTIMPLEMENTED() << "windowless not implemented";
110 return false;
111 // instance_->set_window_handle(parent_);
112 // CreateDummyWindowForActivation();
113 // handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
114 } else {
115 if (!WindowedCreatePlugin())
116 return false;
117 }
118
119 plugin->SetWindow(windowed_handle_, /* unused event param */ NULL);
120 plugin_url_ = url.spec();
121
122 return true;
123 }
124
125 void WebPluginDelegateImpl::DestroyInstance() {
126 if (instance_ && (instance_->npp()->ndata != NULL)) {
127 // Shutdown all streams before destroying so that
128 // no streams are left "in progress". Need to do
129 // this before calling set_web_plugin(NULL) because the
130 // instance uses the helper to do the download.
131 instance_->CloseStreams();
132
133 window_.window = NULL;
134 // if (!(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) {
135 instance_->NPP_SetWindow(&window_);
136 // }
137
138 instance_->NPP_Destroy();
139
140 instance_->set_web_plugin(NULL);
141
142 instance_ = 0;
143 }
144 }
145
146 void WebPluginDelegateImpl::UpdateGeometry(
147 const gfx::Rect& window_rect,
148 const gfx::Rect& clip_rect) {
149 if (windowless_) {
150 WindowlessUpdateGeometry(window_rect, clip_rect);
151 } else {
152 WindowedUpdateGeometry(window_rect, clip_rect);
153 }
154 }
155
156 void WebPluginDelegateImpl::Paint(void* dc, const gfx::Rect& rect) {
157 if (windowless_) {
158 // TODO(port): windowless painting.
159 // WindowlessPaint(dc, rect);
160 }
161 }
162
163 void WebPluginDelegateImpl::Print(void* dc) {
164 NOTIMPLEMENTED();
165 }
166
167 NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
168 return instance_->GetPluginScriptableObject();
169 }
170
171 void WebPluginDelegateImpl::DidFinishLoadWithReason(NPReason reason) {
172 instance()->DidFinishLoadWithReason(reason);
173 }
174
175 int WebPluginDelegateImpl::GetProcessId() {
176 // We are in process, so the plugin pid is this current process pid.
177 return base::GetCurrentProcId();
178 }
179
180 void WebPluginDelegateImpl::SendJavaScriptStream(const std::string& url,
181 const std::wstring& result,
182 bool success,
183 bool notify_needed,
184 int notify_data) {
185 instance()->SendJavaScriptStream(url, result, success, notify_needed,
186 notify_data);
187 }
188
189 void WebPluginDelegateImpl::DidReceiveManualResponse(
190 const std::string& url, const std::string& mime_type,
191 const std::string& headers, uint32 expected_length, uint32 last_modified) {
192 if (!windowless_) {
193 // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in
194 // Flash. See http://b/issue?id=892174.
195 // XXX DCHECK(windowed_did_set_window_);
196 }
197
198 instance()->DidReceiveManualResponse(url, mime_type, headers,
199 expected_length, last_modified);
200 }
201
202 void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
203 int length) {
204 instance()->DidReceiveManualData(buffer, length);
205 }
206
207 void WebPluginDelegateImpl::DidFinishManualLoading() {
208 instance()->DidFinishManualLoading();
209 }
210
211 void WebPluginDelegateImpl::DidManualLoadFail() {
212 instance()->DidManualLoadFail();
213 }
214
215 FilePath WebPluginDelegateImpl::GetPluginPath() {
216 return instance()->plugin_lib()->plugin_info().path;
217 }
218
219 void WebPluginDelegateImpl::InstallMissingPlugin() {
220 /* XXX NPEvent evt;
221 evt.event = PluginInstallerImpl::kInstallMissingPluginMessage;
222 evt.lParam = 0;
223 evt.wParam = 0;
224 instance()->NPP_HandleEvent(&evt); */
225 }
226
227 void WebPluginDelegateImpl::WindowedUpdateGeometry(
228 const gfx::Rect& window_rect,
229 const gfx::Rect& clip_rect) {
230 if (WindowedReposition(window_rect, clip_rect) ||
231 false) { // !windowed_did_set_window_) {
232 // Let the plugin know that it has been moved
233 WindowedSetWindow();
234 }
235 }
236
237 bool WebPluginDelegateImpl::WindowedCreatePlugin() {
238 DCHECK(!windowed_handle_);
239
240 bool xembed;
241 NPError err = instance_->NPP_GetValue(NPPVpluginNeedsXEmbed, &xembed);
242 DCHECK(err == NPERR_NO_ERROR);
243 if (!xembed) {
244 NOTIMPLEMENTED() << "Windowed plugin but without xembed.";
245 return false;
246 }
247
248 windowed_handle_ = gtk_socket_new();
249 gtk_widget_set_parent(windowed_handle_, parent_);
250 // TODO(evanm): connect to signals on the socket, like when the other side
251 // goes away.
252
253 window_.window = GINT_TO_POINTER(
254 gtk_socket_get_id(GTK_SOCKET(windowed_handle_)));
255 gtk_widget_show(windowed_handle_);
256
257 NPSetWindowCallbackStruct* extra = new NPSetWindowCallbackStruct;
258 extra->display = GDK_WINDOW_XDISPLAY(windowed_handle_->window);
259 GdkVisual* visual = gdk_drawable_get_visual(windowed_handle_->window);
260 extra->visual = GDK_VISUAL_XVISUAL(visual);
261 extra->depth = visual->depth;
262 extra->colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(windowed_ha ndle_->window));
263 window_.ws_info = extra;
264
265 return true;
266 }
267
268 void WebPluginDelegateImpl::WindowedDestroyWindow() {
269 #if 0
270 if (windowed_handle_ != NULL) {
271 // Unsubclass the window.
272 WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
273 GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
274 if (current_wnd_proc == NativeWndProc) {
275 SetWindowLongPtr(windowed_handle_,
276 GWLP_WNDPROC,
277 reinterpret_cast<LONG>(plugin_wnd_proc_));
278 }
279
280 DestroyWindow(windowed_handle_);
281 windowed_handle_ = 0;
282 }
283 #endif
284 }
285
286 bool WebPluginDelegateImpl::WindowedReposition(
287 const gfx::Rect& window_rect,
288 const gfx::Rect& clip_rect) {
289 if (!windowed_handle_) {
290 NOTREACHED();
291 return false;
292 }
293
294 if (window_rect_ == window_rect && clip_rect_ == clip_rect)
295 return false;
296
297 // Clipping is handled by WebPlugin.
298 if (window_rect.size() != window_rect_.size()) {
299 gdk_window_resize(windowed_handle_->window,
300 window_rect.width(),
301 window_rect.height());
302 }
303
304 GtkAllocation allocation = { window_rect_.x(), window_rect_.y(),
305 window_rect_.width(), window_rect_.height() };
306 gtk_widget_size_allocate(windowed_handle_, &allocation);
307
308 window_rect_ = window_rect;
309 clip_rect_ = clip_rect;
310
311 // Ensure that the entire window gets repainted.
312 gtk_widget_queue_draw(windowed_handle_);
313
314 return true;
315 }
316
317 void WebPluginDelegateImpl::WindowedSetWindow() {
318 if (!instance_)
319 return;
320
321 if (!windowed_handle_) {
322 NOTREACHED();
323 return;
324 }
325
326 // XXX instance()->set_window_handle(windowed_handle_);
327
328 DCHECK(!instance()->windowless());
329
330 window_.clipRect.top = clip_rect_.y();
331 window_.clipRect.left = clip_rect_.x();
332 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
333 window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
334 window_.height = window_rect_.height();
335 window_.width = window_rect_.width();
336 window_.x = window_rect_.x();
337 window_.y = window_rect_.y();
338
339 //window_.window = windowed_handle_;
340 window_.type = NPWindowTypeWindow;
341
342 // Reset this flag before entering the instance in case of side-effects.
343 // XXX windowed_did_set_window_ = true;
344
345 NPError err = instance()->NPP_SetWindow(&window_);
346 DCHECK(err == NPERR_NO_ERROR);
347 #if 0
348 if (quirks_ & PLUGIN_QUIRK_SETWINDOW_TWICE)
349 instance()->NPP_SetWindow(&window_);
350
351 WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
352 GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
353 if (current_wnd_proc != NativeWndProc) {
354 plugin_wnd_proc_ = reinterpret_cast<WNDPROC>(SetWindowLongPtr(
355 windowed_handle_, GWLP_WNDPROC, reinterpret_cast<LONG>(NativeWndProc)));
356 }
357 #endif
358 }
359
360 void WebPluginDelegateImpl::WindowlessUpdateGeometry(
361 const gfx::Rect& window_rect,
362 const gfx::Rect& clip_rect) {
363 // Only resend to the instance if the geometry has changed.
364 if (window_rect == window_rect_ && clip_rect == clip_rect_)
365 return;
366 /*
367 // Set this flag before entering the instance in case of side-effects.
368 windowless_needs_set_window_ = true;
369
370 // We will inform the instance of this change when we call NPP_SetWindow.
371 clip_rect_ = clip_rect;
372 cutout_rects_.clear();
373
374 if (window_rect_ != window_rect) {
375 window_rect_ = window_rect;
376
377 WindowlessSetWindow(true);
378
379 WINDOWPOS win_pos = {0};
380 win_pos.x = window_rect_.x();
381 win_pos.y = window_rect_.y();
382 win_pos.cx = window_rect_.width();
383 win_pos.cy = window_rect_.height();
384
385 NPEvent pos_changed_event;
386 pos_changed_event.event = WM_WINDOWPOSCHANGED;
387 pos_changed_event.wParam = 0;
388 pos_changed_event.lParam = PtrToUlong(&win_pos);
389
390 instance()->NPP_HandleEvent(&pos_changed_event);
391 }
392 */
393 }
394
395 #if 0
396 void WebPluginDelegateImpl::WindowlessPaint(HDC hdc,
397 const gfx::Rect& damage_rect) {
398 DCHECK(hdc);
399
400 RECT damage_rect_win;
401 damage_rect_win.left = damage_rect.x(); // + window_rect_.x();
402 damage_rect_win.top = damage_rect.y(); // + window_rect_.y();
403 damage_rect_win.right = damage_rect_win.left + damage_rect.width();
404 damage_rect_win.bottom = damage_rect_win.top + damage_rect.height();
405
406 // We need to pass the HDC to the plugin via NPP_SetWindow in the
407 // first paint to ensure that it initiates rect invalidations.
408 if (window_.window == NULL)
409 windowless_needs_set_window_ = true;
410
411 window_.window = hdc;
412 // TODO(darin): we should avoid calling NPP_SetWindow here since it may
413 // cause page layout to be invalidated.
414
415 // We really don't need to continually call SetWindow.
416 // m_needsSetWindow flags when the geometry has changed.
417 if (windowless_needs_set_window_)
418 WindowlessSetWindow(false);
419
420 NPEvent paint_event;
421 paint_event.event = WM_PAINT;
422 // NOTE: NPAPI is not 64bit safe. It puts pointers into 32bit values.
423 paint_event.wParam = PtrToUlong(hdc);
424 paint_event.lParam = PtrToUlong(&damage_rect_win);
425 static StatsRate plugin_paint("Plugin.Paint");
426 StatsScope<StatsRate> scope(plugin_paint);
427 instance()->NPP_HandleEvent(&paint_event);
428 }
429 #endif
430
431 void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
432 if (!instance())
433 return;
434
435 if (window_rect_.IsEmpty()) // wait for geometry to be set.
436 return;
437
438 DCHECK(instance()->windowless());
439
440 window_.clipRect.top = clip_rect_.y();
441 window_.clipRect.left = clip_rect_.x();
442 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
443 window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
444 window_.height = window_rect_.height();
445 window_.width = window_rect_.width();
446 window_.x = window_rect_.x();
447 window_.y = window_rect_.y();
448 window_.type = NPWindowTypeDrawable;
449
450 NPError err = instance()->NPP_SetWindow(&window_);
451 DCHECK(err == NPERR_NO_ERROR);
452 }
453
454 void WebPluginDelegateImpl::SetFocus() {
455 DCHECK(instance()->windowless());
456
457 NOTIMPLEMENTED();
458 /* NPEvent focus_event;
459 focus_event.event = WM_SETFOCUS;
460 focus_event.wParam = 0;
461 focus_event.lParam = 0;
462
463 instance()->NPP_HandleEvent(&focus_event);*/
464 }
465
466 bool WebPluginDelegateImpl::HandleEvent(NPEvent* event,
467 WebCursor* cursor) {
468 NOTIMPLEMENTED();
469 #if 0
470 DCHECK(windowless_) << "events should only be received in windowless mode";
471 DCHECK(cursor != NULL);
472
473 // To ensure that the plugin receives keyboard events we set focus to the
474 // dummy window.
475 // TODO(iyengar) We need a framework in the renderer to identify which
476 // windowless plugin is under the mouse and to handle this. This would
477 // also require some changes in RenderWidgetHost to detect this in the
478 // WM_MOUSEACTIVATE handler and inform the renderer accordingly.
479 HWND prev_focus_window = NULL;
480 if (event->event == WM_RBUTTONDOWN) {
481 prev_focus_window = ::SetFocus(dummy_window_for_activation_);
482 }
483
484 if (ShouldTrackEventForModalLoops(event)) {
485 // A windowless plugin can enter a modal loop in a NPP_HandleEvent call.
486 // For e.g. Flash puts up a context menu when we right click on the
487 // windowless plugin area. We detect this by setting up a message filter
488 // hook pror to calling NPP_HandleEvent on the plugin and unhook on
489 // return from NPP_HandleEvent. If the plugin does enter a modal loop
490 // in that context we unhook on receiving the first notification in
491 // the message filter hook.
492 handle_event_message_filter_hook_ =
493 SetWindowsHookEx(WH_MSGFILTER, HandleEventMessageFilterHook, NULL,
494 GetCurrentThreadId());
495 }
496
497 bool old_task_reentrancy_state =
498 MessageLoop::current()->NestableTasksAllowed();
499
500 current_plugin_instance_ = this;
501
502 handle_event_depth_++;
503
504 bool pop_user_gesture = false;
505
506 if (IsUserGestureMessage(event->event)) {
507 pop_user_gesture = true;
508 instance()->PushPopupsEnabledState(true);
509 }
510
511 bool ret = instance()->NPP_HandleEvent(event) != 0;
512
513 if (event->event == WM_MOUSEMOVE) {
514 // Snag a reference to the current cursor ASAP in case the plugin modified
515 // it. There is a nasty race condition here with the multiprocess browser
516 // as someone might be setting the cursor in the main process as well.
517 *cursor = current_windowless_cursor_;
518 }
519
520 if (pop_user_gesture) {
521 instance()->PopPopupsEnabledState();
522 }
523
524 handle_event_depth_--;
525
526 current_plugin_instance_ = NULL;
527
528 MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state);
529
530 if (handle_event_message_filter_hook_) {
531 UnhookWindowsHookEx(handle_event_message_filter_hook_);
532 handle_event_message_filter_hook_ = NULL;
533 }
534
535 // We could have multiple NPP_HandleEvent calls nested together in case
536 // the plugin enters a modal loop. Reset the pump messages event when
537 // the outermost NPP_HandleEvent call unwinds.
538 if (handle_event_depth_ == 0) {
539 ResetEvent(handle_event_pump_messages_event_);
540 }
541
542 if (event->event == WM_RBUTTONUP && ::IsWindow(prev_focus_window)) {
543 ::SetFocus(prev_focus_window);
544 }
545
546 return ret;
547 #endif
548 return 0;
549 }
550
551 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
552 int resource_id, const std::string &url, bool notify_needed,
553 void *notify_data, void* existing_stream) {
554 // Stream already exists. This typically happens for range requests
555 // initiated via NPN_RequestRead.
556 if (existing_stream) {
557 NPAPI::PluginStream* plugin_stream =
558 reinterpret_cast<NPAPI::PluginStream*>(existing_stream);
559
560 plugin_stream->CancelRequest();
561
562 return plugin_stream->AsResourceClient();
563 }
564
565 if (notify_needed) {
566 instance()->SetURLLoadData(GURL(url.c_str()), notify_data);
567 }
568 std::string mime_type;
569 NPAPI::PluginStreamUrl *stream = instance()->CreateStream(resource_id,
570 url,
571 mime_type,
572 notify_needed,
573 notify_data);
574 return stream;
575 }
576
577 void WebPluginDelegateImpl::URLRequestRouted(const std::string&url,
578 bool notify_needed,
579 void* notify_data) {
580 if (notify_needed) {
581 instance()->SetURLLoadData(GURL(url.c_str()), notify_data);
582 }
583 }
584
585
OLDNEW
« no previous file with comments | « webkit/glue/plugins/webplugin_delegate_impl.h ('k') | webkit/glue/webplugin_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698