OLD | NEW |
(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 |
OLD | NEW |