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

Side by Side Diff: content/child/npapi/webplugin_delegate_impl_win.cc

Issue 1815593002: Remove windowed NPAPI code (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@make_test_plugin_windowless
Patch Set: rebase Created 4 years, 9 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/child/npapi/webplugin_delegate_impl.h" 5 #include "content/child/npapi/webplugin_delegate_impl.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <string.h> 8 #include <string.h>
9 9
10 #include <map> 10 #include <map>
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 // Flash can easily exceed the limits of our CPU if we don't throttle it. 51 // Flash can easily exceed the limits of our CPU if we don't throttle it.
52 // The throttle has been chosen by testing various delays and compromising 52 // The throttle has been chosen by testing various delays and compromising
53 // on acceptable Flash performance and reasonable CPU consumption. 53 // on acceptable Flash performance and reasonable CPU consumption.
54 // 54 //
55 // I'd like to make the throttle delay variable, based on the amount of 55 // I'd like to make the throttle delay variable, based on the amount of
56 // time currently required to paint Flash plugins. There isn't a good 56 // time currently required to paint Flash plugins. There isn't a good
57 // way to count the time spent in aggregate plugin painting, however, so 57 // way to count the time spent in aggregate plugin painting, however, so
58 // this seems to work well enough. 58 // this seems to work well enough.
59 const int kFlashWMUSERMessageThrottleDelayMs = 5; 59 const int kFlashWMUSERMessageThrottleDelayMs = 5;
60 60
61 // Flash displays popups in response to user clicks by posting a WM_USER
62 // message to the plugin window. The handler for this message displays
63 // the popup. To ensure that the popups allowed state is sent correctly
64 // to the renderer we reset the popups allowed state in a timer.
65 const int kWindowedPluginPopupTimerMs = 50;
66
67 // The current instance of the plugin which entered the modal loop. 61 // The current instance of the plugin which entered the modal loop.
68 WebPluginDelegateImpl* g_current_plugin_instance = NULL; 62 WebPluginDelegateImpl* g_current_plugin_instance = NULL;
69 63
70 typedef std::deque<MSG> ThrottleQueue; 64 typedef std::deque<MSG> ThrottleQueue;
71 base::LazyInstance<ThrottleQueue> g_throttle_queue = LAZY_INSTANCE_INITIALIZER; 65 base::LazyInstance<ThrottleQueue> g_throttle_queue = LAZY_INSTANCE_INITIALIZER;
72 66
73 base::LazyInstance<std::map<HWND, WNDPROC> > g_window_handle_proc_map = 67 base::LazyInstance<std::map<HWND, WNDPROC> > g_window_handle_proc_map =
74 LAZY_INSTANCE_INITIALIZER; 68 LAZY_INSTANCE_INITIALIZER;
75 69
76 // Helper object for patching the TrackPopupMenu API. 70 // Helper object for patching the TrackPopupMenu API.
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 LRESULT CALLBACK WebPluginDelegateImpl::HandleEventMessageFilterHook( 199 LRESULT CALLBACK WebPluginDelegateImpl::HandleEventMessageFilterHook(
206 int code, WPARAM wParam, LPARAM lParam) { 200 int code, WPARAM wParam, LPARAM lParam) {
207 if (g_current_plugin_instance) { 201 if (g_current_plugin_instance) {
208 g_current_plugin_instance->OnModalLoopEntered(); 202 g_current_plugin_instance->OnModalLoopEntered();
209 } else { 203 } else {
210 NOTREACHED(); 204 NOTREACHED();
211 } 205 }
212 return CallNextHookEx(NULL, code, wParam, lParam); 206 return CallNextHookEx(NULL, code, wParam, lParam);
213 } 207 }
214 208
215 LRESULT CALLBACK WebPluginDelegateImpl::MouseHookProc(
216 int code, WPARAM wParam, LPARAM lParam) {
217 if (code == HC_ACTION) {
218 MOUSEHOOKSTRUCT* hook_struct = reinterpret_cast<MOUSEHOOKSTRUCT*>(lParam);
219 if (hook_struct)
220 HandleCaptureForMessage(hook_struct->hwnd, wParam);
221 }
222
223 return CallNextHookEx(NULL, code, wParam, lParam);
224 }
225
226 WebPluginDelegateImpl::WebPluginDelegateImpl(WebPlugin* plugin, 209 WebPluginDelegateImpl::WebPluginDelegateImpl(WebPlugin* plugin,
227 PluginInstance* instance) 210 PluginInstance* instance)
228 : windowed_handle_(NULL), 211 : plugin_(plugin),
229 windowed_did_set_window_(false),
230 windowless_(false),
231 plugin_(plugin),
232 instance_(instance), 212 instance_(instance),
233 plugin_wnd_proc_(NULL),
234 last_message_(0),
235 is_calling_wndproc(false),
236 quirks_(0), 213 quirks_(0),
237 dummy_window_for_activation_(NULL), 214 dummy_window_for_activation_(NULL),
238 dummy_window_parent_(NULL), 215 dummy_window_parent_(NULL),
239 old_dummy_window_proc_(NULL), 216 old_dummy_window_proc_(NULL),
240 handle_event_message_filter_hook_(NULL), 217 handle_event_message_filter_hook_(NULL),
241 handle_event_pump_messages_event_(NULL), 218 handle_event_pump_messages_event_(NULL),
242 user_gesture_message_posted_(false),
243 mouse_hook_(NULL),
244 handle_event_depth_(0), 219 handle_event_depth_(0),
245 first_set_window_call_(true), 220 first_set_window_call_(true),
246 plugin_has_focus_(false), 221 plugin_has_focus_(false),
247 has_webkit_focus_(false), 222 has_webkit_focus_(false),
248 containing_view_has_focus_(true), 223 containing_view_has_focus_(true),
249 creation_succeeded_(false), 224 creation_succeeded_(false),
250 user_gesture_msg_factory_(this) { 225 user_gesture_msg_factory_(this) {
251 memset(&window_, 0, sizeof(window_)); 226 memset(&window_, 0, sizeof(window_));
252 227
253 const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info(); 228 const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 if (current_wnd_proc == DummyWindowProc) { 301 if (current_wnd_proc == DummyWindowProc) {
327 SetWindowLongPtr(dummy_window_for_activation_, 302 SetWindowLongPtr(dummy_window_for_activation_,
328 GWLP_WNDPROC, 303 GWLP_WNDPROC,
329 reinterpret_cast<LONG_PTR>(old_dummy_window_proc_)); 304 reinterpret_cast<LONG_PTR>(old_dummy_window_proc_));
330 } 305 }
331 ::DestroyWindow(dummy_window_for_activation_); 306 ::DestroyWindow(dummy_window_for_activation_);
332 } 307 }
333 308
334 DestroyInstance(); 309 DestroyInstance();
335 310
336 if (!windowless_)
337 WindowedDestroyWindow();
338
339 if (handle_event_pump_messages_event_) { 311 if (handle_event_pump_messages_event_) {
340 CloseHandle(handle_event_pump_messages_event_); 312 CloseHandle(handle_event_pump_messages_event_);
341 } 313 }
342 } 314 }
343 315
344 bool WebPluginDelegateImpl::PlatformInitialize() { 316 bool WebPluginDelegateImpl::PlatformInitialize() {
345 plugin_->SetWindow(windowed_handle_); 317 CreateDummyWindowForActivation();
346 318 handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
347 if (windowless_) { 319 plugin_->SetWindowlessData(
348 CreateDummyWindowForActivation(); 320 handle_event_pump_messages_event_,
349 handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); 321 reinterpret_cast<gfx::NativeViewId>(dummy_window_for_activation_));
350 plugin_->SetWindowlessData(
351 handle_event_pump_messages_event_,
352 reinterpret_cast<gfx::NativeViewId>(dummy_window_for_activation_));
353 }
354 322
355 // Windowless plugins call the WindowFromPoint API and passes the result of 323 // Windowless plugins call the WindowFromPoint API and passes the result of
356 // that to the TrackPopupMenu API call as the owner window. This causes the 324 // that to the TrackPopupMenu API call as the owner window. This causes the
357 // API to fail as the API expects the window handle to live on the same 325 // API to fail as the API expects the window handle to live on the same
358 // thread as the caller. It works in the other browsers as the plugin lives 326 // thread as the caller. It works in the other browsers as the plugin lives
359 // on the browser thread. Our workaround is to intercept the TrackPopupMenu 327 // on the browser thread. Our workaround is to intercept the TrackPopupMenu
360 // API and replace the window handle with the dummy activation window. 328 // API and replace the window handle with the dummy activation window.
361 if (windowless_ && !g_iat_patch_track_popup_menu.Pointer()->is_patched()) { 329 if (!g_iat_patch_track_popup_menu.Pointer()->is_patched()) {
362 g_iat_patch_track_popup_menu.Pointer()->Patch( 330 g_iat_patch_track_popup_menu.Pointer()->Patch(
363 GetPluginPath().value().c_str(), "user32.dll", "TrackPopupMenu", 331 GetPluginPath().value().c_str(), "user32.dll", "TrackPopupMenu",
364 WebPluginDelegateImpl::TrackPopupMenuPatch); 332 WebPluginDelegateImpl::TrackPopupMenuPatch);
365 } 333 }
366 334
367 // Windowless plugins can set cursors by calling the SetCursor API. This 335 // Windowless plugins can set cursors by calling the SetCursor API. This
368 // works because the thread inputs of the browser UI thread and the plugin 336 // works because the thread inputs of the browser UI thread and the plugin
369 // thread are attached. We intercept the SetCursor API for windowless 337 // thread are attached. We intercept the SetCursor API for windowless
370 // plugins and remember the cursor being set. This is shipped over to the 338 // plugins and remember the cursor being set. This is shipped over to the
371 // browser in the HandleEvent call, which ensures that the cursor does not 339 // browser in the HandleEvent call, which ensures that the cursor does not
372 // change when a windowless plugin instance changes the cursor 340 // change when a windowless plugin instance changes the cursor
373 // in a background tab. 341 // in a background tab.
374 if (windowless_ && !g_iat_patch_set_cursor.Pointer()->is_patched() && 342 if (!g_iat_patch_set_cursor.Pointer()->is_patched() &&
375 (quirks_ & PLUGIN_QUIRK_PATCH_SETCURSOR)) { 343 (quirks_ & PLUGIN_QUIRK_PATCH_SETCURSOR)) {
376 g_iat_patch_set_cursor.Pointer()->Patch( 344 g_iat_patch_set_cursor.Pointer()->Patch(
377 GetPluginPath().value().c_str(), "user32.dll", "SetCursor", 345 GetPluginPath().value().c_str(), "user32.dll", "SetCursor",
378 WebPluginDelegateImpl::SetCursorPatch); 346 WebPluginDelegateImpl::SetCursorPatch);
379 } 347 }
380 348
381 // The windowed flash plugin has a bug which occurs when the plugin enters
382 // fullscreen mode. It basically captures the mouse on WM_LBUTTONDOWN and
383 // does not release capture correctly causing it to stop receiving
384 // subsequent mouse events. This problem is also seen in Safari where there
385 // is code to handle this in the wndproc. However the plugin subclasses the
386 // window again in WM_LBUTTONDOWN before entering full screen. As a result
387 // Safari does not receive the WM_LBUTTONUP message. To workaround this
388 // issue we use a per thread mouse hook. This bug does not occur in Firefox
389 // and opera. Firefox has code similar to Safari. It could well be a bug in
390 // the flash plugin, which only occurs in webkit based browsers.
391 if (quirks_ & PLUGIN_QUIRK_HANDLE_MOUSE_CAPTURE) {
392 mouse_hook_ = SetWindowsHookEx(WH_MOUSE, MouseHookProc, NULL,
393 GetCurrentThreadId());
394 }
395
396 // On XP, WMP will use its old UI unless a registry key under HKLM has the 349 // On XP, WMP will use its old UI unless a registry key under HKLM has the
397 // name of the current process. We do it in the installer for admin users, 350 // name of the current process. We do it in the installer for admin users,
398 // for the rest patch this function. 351 // for the rest patch this function.
399 if ((quirks_ & PLUGIN_QUIRK_PATCH_REGENUMKEYEXW) && 352 if ((quirks_ & PLUGIN_QUIRK_PATCH_REGENUMKEYEXW) &&
400 base::win::GetVersion() == base::win::VERSION_XP && 353 base::win::GetVersion() == base::win::VERSION_XP &&
401 (base::win::RegKey().Open(HKEY_LOCAL_MACHINE, 354 (base::win::RegKey().Open(HKEY_LOCAL_MACHINE,
402 L"SOFTWARE\\Microsoft\\MediaPlayer\\ShimInclusionList\\chrome.exe", 355 L"SOFTWARE\\Microsoft\\MediaPlayer\\ShimInclusionList\\chrome.exe",
403 KEY_READ) != ERROR_SUCCESS) && 356 KEY_READ) != ERROR_SUCCESS) &&
404 !g_iat_patch_reg_enum_key_ex_w.Pointer()->is_patched()) { 357 !g_iat_patch_reg_enum_key_ex_w.Pointer()->is_patched()) {
405 g_iat_patch_reg_enum_key_ex_w.Pointer()->Patch( 358 g_iat_patch_reg_enum_key_ex_w.Pointer()->Patch(
406 L"wmpdxm.dll", "advapi32.dll", "RegEnumKeyExW", 359 L"wmpdxm.dll", "advapi32.dll", "RegEnumKeyExW",
407 WebPluginDelegateImpl::RegEnumKeyExWPatch); 360 WebPluginDelegateImpl::RegEnumKeyExWPatch);
408 } 361 }
409 362
410 // Flash retrieves the pointers to IMM32 functions with GetProcAddress() calls 363 // Flash retrieves the pointers to IMM32 functions with GetProcAddress() calls
411 // and use them to retrieve IME data. We add a patch to this function so we 364 // and use them to retrieve IME data. We add a patch to this function so we
412 // can dispatch these IMM32 calls to the WebPluginIMEWin class, which emulates 365 // can dispatch these IMM32 calls to the WebPluginIMEWin class, which emulates
413 // IMM32 functions for Flash. 366 // IMM32 functions for Flash.
414 if (!g_iat_patch_get_proc_address.Pointer()->is_patched() && 367 if (!g_iat_patch_get_proc_address.Pointer()->is_patched() &&
415 (quirks_ & PLUGIN_QUIRK_EMULATE_IME)) { 368 (quirks_ & PLUGIN_QUIRK_EMULATE_IME)) {
416 g_iat_patch_get_proc_address.Pointer()->Patch( 369 g_iat_patch_get_proc_address.Pointer()->Patch(
417 GetPluginPath().value().c_str(), "kernel32.dll", "GetProcAddress", 370 GetPluginPath().value().c_str(), "kernel32.dll", "GetProcAddress",
418 GetProcAddressPatch); 371 GetProcAddressPatch);
419 } 372 }
420 373
421 if (windowless_ && !g_iat_patch_window_from_point.Pointer()->is_patched() && 374 if (!g_iat_patch_window_from_point.Pointer()->is_patched() &&
422 (quirks_ & PLUGIN_QUIRK_FAKE_WINDOW_FROM_POINT)) { 375 (quirks_ & PLUGIN_QUIRK_FAKE_WINDOW_FROM_POINT)) {
423 g_iat_patch_window_from_point.Pointer()->Patch( 376 g_iat_patch_window_from_point.Pointer()->Patch(
424 GetPluginPath().value().c_str(), "user32.dll", "WindowFromPoint", 377 GetPluginPath().value().c_str(), "user32.dll", "WindowFromPoint",
425 WebPluginDelegateImpl::WindowFromPointPatch); 378 WebPluginDelegateImpl::WindowFromPointPatch);
426 } 379 }
427 380
428 return true; 381 return true;
429 } 382 }
430 383
431 void WebPluginDelegateImpl::PlatformDestroyInstance() { 384 void WebPluginDelegateImpl::PlatformDestroyInstance() {
432 if (!instance_->plugin_lib()) 385 if (!instance_->plugin_lib())
433 return; 386 return;
434 387
435 // Unpatch if this is the last plugin instance. 388 // Unpatch if this is the last plugin instance.
436 if (instance_->plugin_lib()->instance_count() != 1) 389 if (instance_->plugin_lib()->instance_count() != 1)
437 return; 390 return;
438 391
439 if (g_iat_patch_set_cursor.Pointer()->is_patched()) 392 if (g_iat_patch_set_cursor.Pointer()->is_patched())
440 g_iat_patch_set_cursor.Pointer()->Unpatch(); 393 g_iat_patch_set_cursor.Pointer()->Unpatch();
441 394
442 if (g_iat_patch_track_popup_menu.Pointer()->is_patched()) 395 if (g_iat_patch_track_popup_menu.Pointer()->is_patched())
443 g_iat_patch_track_popup_menu.Pointer()->Unpatch(); 396 g_iat_patch_track_popup_menu.Pointer()->Unpatch();
444 397
445 if (g_iat_patch_reg_enum_key_ex_w.Pointer()->is_patched()) 398 if (g_iat_patch_reg_enum_key_ex_w.Pointer()->is_patched())
446 g_iat_patch_reg_enum_key_ex_w.Pointer()->Unpatch(); 399 g_iat_patch_reg_enum_key_ex_w.Pointer()->Unpatch();
447 400
448 if (g_iat_patch_window_from_point.Pointer()->is_patched()) 401 if (g_iat_patch_window_from_point.Pointer()->is_patched())
449 g_iat_patch_window_from_point.Pointer()->Unpatch(); 402 g_iat_patch_window_from_point.Pointer()->Unpatch();
450
451 if (mouse_hook_) {
452 UnhookWindowsHookEx(mouse_hook_);
453 mouse_hook_ = NULL;
454 }
455 } 403 }
456 404
457 void WebPluginDelegateImpl::Paint(SkCanvas* canvas, const gfx::Rect& rect) { 405 void WebPluginDelegateImpl::Paint(SkCanvas* canvas, const gfx::Rect& rect) {
458 if (windowless_ && skia::SupportsPlatformPaint(canvas)) { 406 if (skia::SupportsPlatformPaint(canvas)) {
459 skia::ScopedPlatformPaint scoped_platform_paint(canvas); 407 skia::ScopedPlatformPaint scoped_platform_paint(canvas);
460 HDC hdc = scoped_platform_paint.GetPlatformSurface(); 408 HDC hdc = scoped_platform_paint.GetPlatformSurface();
461 WindowlessPaint(hdc, rect); 409 WindowlessPaint(hdc, rect);
462 } 410 }
463 } 411 }
464 412
465 bool WebPluginDelegateImpl::WindowedCreatePlugin() {
466 DCHECK(!windowed_handle_);
467
468 RegisterNativeWindowClass();
469
470 // The window will be sized and shown later.
471 windowed_handle_ = CreateWindowEx(
472 WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
473 kNativeWindowClassName,
474 0,
475 WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
476 0,
477 0,
478 0,
479 0,
480 GetDesktopWindow(),
481 0,
482 GetModuleHandle(NULL),
483 0);
484 if (windowed_handle_ == 0)
485 return false;
486
487 // This is a tricky workaround for Issue 2673 in chromium "Flash: IME not
488 // available". To use IMEs in this window, we have to make Windows attach
489 // IMEs to this window (i.e. load IME DLLs, attach them to this process, and
490 // add their message hooks to this window). Windows attaches IMEs while this
491 // process creates a top-level window. On the other hand, to layout this
492 // window correctly in the given parent window (RenderWidgetHostViewWin or
493 // RenderWidgetHostViewAura), this window should be a child window of the
494 // parent window. To satisfy both of the above conditions, this code once
495 // creates a top-level window and change it to a child window of the parent
496 // window (in the browser process).
497 SetWindowLongPtr(windowed_handle_, GWL_STYLE,
498 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
499
500 BOOL result = SetProp(windowed_handle_, kWebPluginDelegateProperty, this);
501 DCHECK(result == TRUE) << "SetProp failed, last error = " << GetLastError();
502
503 // Calling SetWindowLongPtrA here makes the window proc ASCII, which is
504 // required by at least the Shockwave Director plugin.
505 SetWindowLongPtrA(windowed_handle_,
506 GWLP_WNDPROC,
507 reinterpret_cast<LONG_PTR>(DefWindowProcA));
508
509 return true;
510 }
511
512 void WebPluginDelegateImpl::WindowedDestroyWindow() {
513 if (windowed_handle_ != NULL) {
514 // Unsubclass the window.
515 WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
516 GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
517 if (current_wnd_proc == NativeWndProc) {
518 SetWindowLongPtr(windowed_handle_,
519 GWLP_WNDPROC,
520 reinterpret_cast<LONG_PTR>(plugin_wnd_proc_));
521 }
522
523 plugin_->WillDestroyWindow(windowed_handle_);
524
525 DestroyWindow(windowed_handle_);
526 windowed_handle_ = 0;
527 }
528 }
529
530 // Erase all messages in the queue destined for a particular window. 413 // Erase all messages in the queue destined for a particular window.
531 // When windows are closing, callers should use this function to clear 414 // When windows are closing, callers should use this function to clear
532 // the queue. 415 // the queue.
533 // static 416 // static
534 void WebPluginDelegateImpl::ClearThrottleQueueForWindow(HWND window) { 417 void WebPluginDelegateImpl::ClearThrottleQueueForWindow(HWND window) {
535 ThrottleQueue* throttle_queue = g_throttle_queue.Pointer(); 418 ThrottleQueue* throttle_queue = g_throttle_queue.Pointer();
536 419
537 ThrottleQueue::iterator it; 420 ThrottleQueue::iterator it;
538 for (it = throttle_queue->begin(); it != throttle_queue->end(); ) { 421 for (it = throttle_queue->begin(); it != throttle_queue->end(); ) {
539 if (it->hwnd == window) { 422 if (it->hwnd == window) {
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 reinterpret_cast<LPARAM>( 631 reinterpret_cast<LPARAM>(
749 &WebPluginDelegateImpl::FlashWindowlessWndProc))) { 632 &WebPluginDelegateImpl::FlashWindowlessWndProc))) {
750 // Log that this happened. Flash will still work; it just means the 633 // Log that this happened. Flash will still work; it just means the
751 // throttle isn't installed (and Flash will use more CPU). 634 // throttle isn't installed (and Flash will use more CPU).
752 NOTREACHED(); 635 NOTREACHED();
753 LOG(ERROR) << "Failed to wrap all windowless Flash windows"; 636 LOG(ERROR) << "Failed to wrap all windowless Flash windows";
754 } 637 }
755 return true; 638 return true;
756 } 639 }
757 640
758 bool WebPluginDelegateImpl::WindowedReposition(
759 const gfx::Rect& window_rect_in_dip,
760 const gfx::Rect& clip_rect_in_dip) {
761 if (!windowed_handle_) {
762 NOTREACHED();
763 return false;
764 }
765
766 gfx::Rect window_rect = gfx::win::DIPToScreenRect(window_rect_in_dip);
767 gfx::Rect clip_rect = gfx::win::DIPToScreenRect(clip_rect_in_dip);
768 if (window_rect_ == window_rect && clip_rect_ == clip_rect)
769 return false;
770
771 // We only set the plugin's size here. Its position is moved elsewhere, which
772 // allows the window moves/scrolling/clipping to be synchronized with the page
773 // and other windows.
774 // If the plugin window has no parent, then don't focus it because it isn't
775 // being displayed anywhere. See:
776 // http://code.google.com/p/chromium/issues/detail?id=32658
777 if (window_rect.size() != window_rect_.size()) {
778 UINT flags = SWP_NOMOVE | SWP_NOZORDER;
779 if (!GetParent(windowed_handle_))
780 flags |= SWP_NOACTIVATE;
781 ::SetWindowPos(windowed_handle_,
782 NULL,
783 0,
784 0,
785 window_rect.width(),
786 window_rect.height(),
787 flags);
788 }
789
790 window_rect_ = window_rect;
791 clip_rect_ = clip_rect;
792
793 // Ensure that the entire window gets repainted.
794 ::InvalidateRect(windowed_handle_, NULL, FALSE);
795
796 return true;
797 }
798
799 void WebPluginDelegateImpl::WindowedSetWindow() {
800 if (!instance_.get())
801 return;
802
803 if (!windowed_handle_) {
804 NOTREACHED();
805 return;
806 }
807
808 instance()->set_window_handle(windowed_handle_);
809
810 DCHECK(!instance()->windowless());
811
812 window_.clipRect.top = std::max(0, clip_rect_.y());
813 window_.clipRect.left = std::max(0, clip_rect_.x());
814 window_.clipRect.bottom = std::max(0, clip_rect_.y() + clip_rect_.height());
815 window_.clipRect.right = std::max(0, clip_rect_.x() + clip_rect_.width());
816 window_.height = window_rect_.height();
817 window_.width = window_rect_.width();
818 window_.x = 0;
819 window_.y = 0;
820
821 window_.window = windowed_handle_;
822 window_.type = NPWindowTypeWindow;
823
824 // Reset this flag before entering the instance in case of side-effects.
825 windowed_did_set_window_ = true;
826
827 instance()->NPP_SetWindow(&window_);
828 if (quirks_ & PLUGIN_QUIRK_SETWINDOW_TWICE)
829 instance()->NPP_SetWindow(&window_);
830
831 WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
832 GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
833 if (current_wnd_proc != NativeWndProc) {
834 plugin_wnd_proc_ = reinterpret_cast<WNDPROC>(
835 SetWindowLongPtr(windowed_handle_,
836 GWLP_WNDPROC,
837 reinterpret_cast<LONG_PTR>(NativeWndProc)));
838 }
839 }
840
841 ATOM WebPluginDelegateImpl::RegisterNativeWindowClass() {
842 static bool have_registered_window_class = false;
843 if (have_registered_window_class == true)
844 return true;
845
846 have_registered_window_class = true;
847
848 WNDCLASSEX wcex;
849 wcex.cbSize = sizeof(WNDCLASSEX);
850 wcex.style = CS_DBLCLKS;
851 wcex.lpfnWndProc = WrapperWindowProc;
852 wcex.cbClsExtra = 0;
853 wcex.cbWndExtra = 0;
854 wcex.hInstance = GetModuleHandle(NULL);
855 wcex.hIcon = 0;
856 wcex.hCursor = 0;
857 // Some plugins like windows media player 11 create child windows parented
858 // by our plugin window, where the media content is rendered. These plugins
859 // dont implement WM_ERASEBKGND, which causes painting issues, when the
860 // window where the media is rendered is moved around. DefWindowProc does
861 // implement WM_ERASEBKGND correctly if we have a valid background brush.
862 wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
863 wcex.lpszMenuName = 0;
864 wcex.lpszClassName = kNativeWindowClassName;
865 wcex.hIconSm = 0;
866
867 return RegisterClassEx(&wcex);
868 }
869
870 LRESULT CALLBACK WebPluginDelegateImpl::WrapperWindowProc(
871 HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
872 // This is another workaround for Issue 2673 in chromium "Flash: IME not
873 // available". Somehow, the CallWindowProc() function does not dispatch
874 // window messages when its first parameter is a handle representing the
875 // DefWindowProc() function. To avoid this problem, this code creates a
876 // wrapper function which just encapsulates the DefWindowProc() function
877 // and set it as the window procedure of a windowed plugin.
878 return DefWindowProc(hWnd, message, wParam, lParam);
879 }
880
881 // Returns true if the message passed in corresponds to a user gesture. 641 // Returns true if the message passed in corresponds to a user gesture.
882 static bool IsUserGestureMessage(unsigned int message) { 642 static bool IsUserGestureMessage(unsigned int message) {
883 switch (message) { 643 switch (message) {
884 case WM_LBUTTONDOWN: 644 case WM_LBUTTONDOWN:
885 case WM_LBUTTONUP: 645 case WM_LBUTTONUP:
886 case WM_RBUTTONDOWN: 646 case WM_RBUTTONDOWN:
887 case WM_RBUTTONUP: 647 case WM_RBUTTONUP:
888 case WM_MBUTTONDOWN: 648 case WM_MBUTTONDOWN:
889 case WM_MBUTTONUP: 649 case WM_MBUTTONUP:
890 case WM_KEYDOWN: 650 case WM_KEYDOWN:
891 case WM_KEYUP: 651 case WM_KEYUP:
892 return true; 652 return true;
893 653
894 default: 654 default:
895 break; 655 break;
896 } 656 }
897 657
898 return false; 658 return false;
899 } 659 }
900 660
901 LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc(
902 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
903 WebPluginDelegateImpl* delegate = reinterpret_cast<WebPluginDelegateImpl*>(
904 GetProp(hwnd, kWebPluginDelegateProperty));
905 if (!delegate) {
906 NOTREACHED();
907 return 0;
908 }
909
910 if (message == delegate->last_message_ &&
911 delegate->GetQuirks() & PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY &&
912 delegate->is_calling_wndproc) {
913 // Real may go into a state where it recursively dispatches the same event
914 // when subclassed. See https://bugzilla.mozilla.org/show_bug.cgi?id=192914
915 // We only do the recursive check for Real because it's possible and valid
916 // for a plugin to synchronously dispatch a message to itself such that it
917 // looks like it's in recursion.
918 return TRUE;
919 }
920
921 // Flash may flood the message queue with WM_USER+1 message causing 100% CPU
922 // usage. See https://bugzilla.mozilla.org/show_bug.cgi?id=132759. We
923 // prevent this by throttling the messages.
924 if (message == WM_USER + 1 &&
925 delegate->GetQuirks() & PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE) {
926 WebPluginDelegateImpl::ThrottleMessage(delegate->plugin_wnd_proc_, hwnd,
927 message, wparam, lparam);
928 return FALSE;
929 }
930
931 LRESULT result;
932 uint32_t old_message = delegate->last_message_;
933 delegate->last_message_ = message;
934
935 static UINT custom_msg = RegisterWindowMessage(kPaintMessageName);
936 if (message == custom_msg) {
937 // Get the invalid rect which is in screen coordinates and convert to
938 // window coordinates.
939 gfx::Rect invalid_rect;
940 invalid_rect.set_x(static_cast<short>(LOWORD(wparam)));
941 invalid_rect.set_y(static_cast<short>(HIWORD(wparam)));
942 invalid_rect.set_width(static_cast<short>(LOWORD(lparam)));
943 invalid_rect.set_height(static_cast<short>(HIWORD(lparam)));
944
945 RECT window_rect;
946 GetWindowRect(hwnd, &window_rect);
947 invalid_rect.Offset(-window_rect.left, -window_rect.top);
948
949 // The plugin window might have non-client area. If we don't pass in
950 // RDW_FRAME then the children don't receive WM_NCPAINT messages while
951 // scrolling, which causes painting problems (http://b/issue?id=923945).
952 uint32_t flags = RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME;
953
954 // If a plugin (like Google Earth or Java) has child windows that are hosted
955 // in a different process, then RedrawWindow with UPDATENOW will
956 // synchronously wait for this call to complete. Some messages are pumped
957 // but not others, which could lead to a deadlock. So avoid reentrancy by
958 // only synchronously calling RedrawWindow once at a time.
959 if (old_message != custom_msg)
960 flags |= RDW_UPDATENOW;
961 RECT rect = invalid_rect.ToRECT();
962 RedrawWindow(hwnd, &rect, NULL, flags);
963 result = FALSE;
964 } else {
965 delegate->is_calling_wndproc = true;
966
967 if (!delegate->user_gesture_message_posted_ &&
968 IsUserGestureMessage(message)) {
969 delegate->user_gesture_message_posted_ = true;
970
971 delegate->instance()->PushPopupsEnabledState(true);
972
973 base::MessageLoop::current()->PostDelayedTask(
974 FROM_HERE,
975 base::Bind(&WebPluginDelegateImpl::OnUserGestureEnd,
976 delegate->user_gesture_msg_factory_.GetWeakPtr()),
977 base::TimeDelta::FromMilliseconds(kWindowedPluginPopupTimerMs));
978 }
979
980 HandleCaptureForMessage(hwnd, message);
981
982 // Maintain a local/global stack for the g_current_plugin_instance variable
983 // as this may be a nested invocation.
984 WebPluginDelegateImpl* last_plugin_instance = g_current_plugin_instance;
985
986 g_current_plugin_instance = delegate;
987
988 result = CallWindowProc(
989 delegate->plugin_wnd_proc_, hwnd, message, wparam, lparam);
990
991 // The plugin instance may have been destroyed in the CallWindowProc call
992 // above. This will also destroy the plugin window. Before attempting to
993 // access the WebPluginDelegateImpl instance we validate if the window is
994 // still valid.
995 if (::IsWindow(hwnd))
996 delegate->is_calling_wndproc = false;
997
998 g_current_plugin_instance = last_plugin_instance;
999
1000 if (message == WM_NCDESTROY) {
1001 RemoveProp(hwnd, kWebPluginDelegateProperty);
1002 ClearThrottleQueueForWindow(hwnd);
1003 }
1004 }
1005 if (::IsWindow(hwnd))
1006 delegate->last_message_ = old_message;
1007 return result;
1008 }
1009
1010 void WebPluginDelegateImpl::WindowlessUpdateGeometry( 661 void WebPluginDelegateImpl::WindowlessUpdateGeometry(
1011 const gfx::Rect& window_rect, 662 const gfx::Rect& window_rect,
1012 const gfx::Rect& clip_rect) { 663 const gfx::Rect& clip_rect) {
1013 bool window_rect_changed = (window_rect_ != window_rect); 664 bool window_rect_changed = (window_rect_ != window_rect);
1014 // Only resend to the instance if the geometry has changed. 665 // Only resend to the instance if the geometry has changed.
1015 if (!window_rect_changed && clip_rect == clip_rect_) 666 if (!window_rect_changed && clip_rect == clip_rect_)
1016 return; 667 return;
1017 668
1018 clip_rect_ = clip_rect; 669 clip_rect_ = clip_rect;
1019 window_rect_ = window_rect; 670 window_rect_ = window_rect;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1058 window_.window = old_dc; 709 window_.window = old_dc;
1059 } 710 }
1060 711
1061 void WebPluginDelegateImpl::WindowlessSetWindow() { 712 void WebPluginDelegateImpl::WindowlessSetWindow() {
1062 if (!instance()) 713 if (!instance())
1063 return; 714 return;
1064 715
1065 if (window_rect_.IsEmpty()) // wait for geometry to be set. 716 if (window_rect_.IsEmpty()) // wait for geometry to be set.
1066 return; 717 return;
1067 718
1068 DCHECK(instance()->windowless());
1069
1070 window_.clipRect.top = clip_rect_.y(); 719 window_.clipRect.top = clip_rect_.y();
1071 window_.clipRect.left = clip_rect_.x(); 720 window_.clipRect.left = clip_rect_.x();
1072 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); 721 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
1073 window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); 722 window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
1074 window_.height = window_rect_.height(); 723 window_.height = window_rect_.height();
1075 window_.width = window_rect_.width(); 724 window_.width = window_rect_.width();
1076 window_.x = window_rect_.x(); 725 window_.x = window_rect_.x();
1077 window_.y = window_rect_.y(); 726 window_.y = window_rect_.y();
1078 window_.type = NPWindowTypeDrawable; 727 window_.type = NPWindowTypeDrawable;
1079 DrawableContextEnforcer enforcer(&window_); 728 DrawableContextEnforcer enforcer(&window_);
1080 729
1081 NPError err = instance()->NPP_SetWindow(&window_); 730 NPError err = instance()->NPP_SetWindow(&window_);
1082 DCHECK(err == NPERR_NO_ERROR); 731 DCHECK(err == NPERR_NO_ERROR);
1083 } 732 }
1084 733
1085 bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) { 734 bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
1086 DCHECK(instance()->windowless());
1087
1088 NPEvent focus_event; 735 NPEvent focus_event;
1089 focus_event.event = focused ? WM_SETFOCUS : WM_KILLFOCUS; 736 focus_event.event = focused ? WM_SETFOCUS : WM_KILLFOCUS;
1090 focus_event.wParam = 0; 737 focus_event.wParam = 0;
1091 focus_event.lParam = 0; 738 focus_event.lParam = 0;
1092 739
1093 instance()->NPP_HandleEvent(&focus_event); 740 instance()->NPP_HandleEvent(&focus_event);
1094 return true; 741 return true;
1095 } 742 }
1096 743
1097 static bool NPEventFromWebMouseEvent(const WebMouseEvent& event, 744 static bool NPEventFromWebMouseEvent(const WebMouseEvent& event,
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
1346 UnhookWindowsHookEx(handle_event_message_filter_hook_); 993 UnhookWindowsHookEx(handle_event_message_filter_hook_);
1347 handle_event_message_filter_hook_ = NULL; 994 handle_event_message_filter_hook_ = NULL;
1348 } 995 }
1349 996
1350 bool WebPluginDelegateImpl::ShouldTrackEventForModalLoops(NPEvent* event) { 997 bool WebPluginDelegateImpl::ShouldTrackEventForModalLoops(NPEvent* event) {
1351 if (event->event == WM_RBUTTONDOWN) 998 if (event->event == WM_RBUTTONDOWN)
1352 return true; 999 return true;
1353 return false; 1000 return false;
1354 } 1001 }
1355 1002
1356 void WebPluginDelegateImpl::OnUserGestureEnd() {
1357 user_gesture_message_posted_ = false;
1358 instance()->PopPopupsEnabledState();
1359 }
1360
1361 BOOL WINAPI WebPluginDelegateImpl::TrackPopupMenuPatch( 1003 BOOL WINAPI WebPluginDelegateImpl::TrackPopupMenuPatch(
1362 HMENU menu, unsigned int flags, int x, int y, int reserved, 1004 HMENU menu, unsigned int flags, int x, int y, int reserved,
1363 HWND window, const RECT* rect) { 1005 HWND window, const RECT* rect) {
1364 1006
1365 if (g_current_plugin_instance) { 1007 if (g_current_plugin_instance) {
1366 unsigned long window_process_id = 0; 1008 unsigned long window_process_id = 0;
1367 unsigned long window_thread_id = 1009 unsigned long window_thread_id =
1368 GetWindowThreadProcessId(window, &window_process_id); 1010 GetWindowThreadProcessId(window, &window_process_id);
1369 // TrackPopupMenu fails if the window passed in belongs to a different 1011 // TrackPopupMenu fails if the window passed in belongs to a different
1370 // thread. 1012 // thread.
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1457 HWND window = WindowFromPoint(point); 1099 HWND window = WindowFromPoint(point);
1458 if (::ScreenToClient(window, &point)) { 1100 if (::ScreenToClient(window, &point)) {
1459 HWND child = ChildWindowFromPoint(window, point); 1101 HWND child = ChildWindowFromPoint(window, point);
1460 if (::IsWindow(child) && 1102 if (::IsWindow(child) &&
1461 ::GetProp(child, content::kPluginDummyParentProperty)) 1103 ::GetProp(child, content::kPluginDummyParentProperty))
1462 return child; 1104 return child;
1463 } 1105 }
1464 return window; 1106 return window;
1465 } 1107 }
1466 1108
1467 void WebPluginDelegateImpl::HandleCaptureForMessage(HWND window,
1468 UINT message) {
1469 if (gfx::GetClassName(window) != base::string16(kNativeWindowClassName))
1470 return;
1471
1472 switch (message) {
1473 case WM_LBUTTONDOWN:
1474 case WM_MBUTTONDOWN:
1475 case WM_RBUTTONDOWN:
1476 ::SetCapture(window);
1477 // As per documentation the WM_PARENTNOTIFY message is sent to the parent
1478 // window chain if mouse input is received by the child window. However
1479 // the parent receives the WM_PARENTNOTIFY message only if we doubleclick
1480 // on the window. We send the WM_PARENTNOTIFY message for mouse input
1481 // messages to the parent to indicate that user action is expected.
1482 ::SendMessage(::GetParent(window), WM_PARENTNOTIFY, message, 0);
1483 break;
1484
1485 case WM_LBUTTONUP:
1486 case WM_MBUTTONUP:
1487 case WM_RBUTTONUP:
1488 ::ReleaseCapture();
1489 break;
1490
1491 default:
1492 break;
1493 }
1494 }
1495
1496 } // namespace content 1109 } // namespace content
OLDNEW
« no previous file with comments | « content/child/npapi/webplugin_delegate_impl_mac.mm ('k') | content/child/npapi/webplugin_ime_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698