| OLD | NEW |
| 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 "webkit/plugins/npapi/webplugin_delegate_impl.h" | 5 #include "webkit/plugins/npapi/webplugin_delegate_impl.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 LAZY_INSTANCE_INITIALIZER; | 85 LAZY_INSTANCE_INITIALIZER; |
| 86 | 86 |
| 87 // Helper object for patching the RegEnumKeyExW API. | 87 // Helper object for patching the RegEnumKeyExW API. |
| 88 base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_reg_enum_key_ex_w = | 88 base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_reg_enum_key_ex_w = |
| 89 LAZY_INSTANCE_INITIALIZER; | 89 LAZY_INSTANCE_INITIALIZER; |
| 90 | 90 |
| 91 // Helper object for patching the GetProcAddress API. | 91 // Helper object for patching the GetProcAddress API. |
| 92 base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_get_proc_address = | 92 base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_get_proc_address = |
| 93 LAZY_INSTANCE_INITIALIZER; | 93 LAZY_INSTANCE_INITIALIZER; |
| 94 | 94 |
| 95 // Helper object for patching the GetKeyState API. | |
| 96 base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_get_key_state = | |
| 97 LAZY_INSTANCE_INITIALIZER; | |
| 98 | |
| 99 // Saved key state globals and helper access functions. | |
| 100 SHORT (WINAPI *g_iat_orig_get_key_state)(int vkey); | |
| 101 typedef size_t SavedStateType; | |
| 102 const size_t kBitsPerType = sizeof(SavedStateType) * 8; | |
| 103 // Bit array of key state corresponding to virtual key index (0=up, 1=down). | |
| 104 SavedStateType g_saved_key_state[256 / kBitsPerType]; | |
| 105 | |
| 106 bool GetSavedKeyState(WPARAM vkey) { | |
| 107 CHECK_LT(vkey, kBitsPerType * sizeof(g_saved_key_state)); | |
| 108 if (g_saved_key_state[vkey / kBitsPerType] & 1 << (vkey % kBitsPerType)) | |
| 109 return true; | |
| 110 return false; | |
| 111 } | |
| 112 | |
| 113 void SetSavedKeyState(WPARAM vkey) { | |
| 114 CHECK_LT(vkey, kBitsPerType * sizeof(g_saved_key_state)); | |
| 115 // Cache the key state only for keys blocked by UIPI. | |
| 116 if (g_iat_orig_get_key_state(vkey) == 0) | |
| 117 g_saved_key_state[vkey / kBitsPerType] |= 1 << (vkey % kBitsPerType); | |
| 118 } | |
| 119 | |
| 120 void UnsetSavedKeyState(WPARAM vkey) { | |
| 121 CHECK_LT(vkey, kBitsPerType * sizeof(g_saved_key_state)); | |
| 122 g_saved_key_state[vkey / kBitsPerType] &= ~(1 << (vkey % kBitsPerType)); | |
| 123 } | |
| 124 | |
| 125 void ClearSavedKeyState() { | |
| 126 memset(g_saved_key_state, 0, sizeof(g_saved_key_state)); | |
| 127 } | |
| 128 | |
| 129 // Helper objects for patching VirtualQuery, VirtualProtect. | |
| 130 base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_virtual_protect = | |
| 131 LAZY_INSTANCE_INITIALIZER; | |
| 132 BOOL (WINAPI *g_iat_orig_virtual_protect)(LPVOID address, | |
| 133 SIZE_T size, | |
| 134 DWORD new_protect, | |
| 135 PDWORD old_protect); | |
| 136 | |
| 137 base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_virtual_free = | |
| 138 LAZY_INSTANCE_INITIALIZER; | |
| 139 BOOL (WINAPI *g_iat_orig_virtual_free)(LPVOID address, | |
| 140 SIZE_T size, | |
| 141 DWORD free_type); | |
| 142 | |
| 143 const DWORD kExecPageMask = PAGE_EXECUTE_READ; | |
| 144 static volatile intptr_t g_max_exec_mem_size; | |
| 145 static scoped_ptr<base::Lock> g_exec_mem_lock; | |
| 146 | |
| 147 void UpdateExecMemSize(intptr_t size) { | |
| 148 base::AutoLock locked(*g_exec_mem_lock); | |
| 149 | |
| 150 static intptr_t s_exec_mem_size = 0; | |
| 151 | |
| 152 // Floor to zero since shutdown may unmap pages created before our hooks. | |
| 153 s_exec_mem_size = std::max(0, s_exec_mem_size + size); | |
| 154 if (s_exec_mem_size > g_max_exec_mem_size) | |
| 155 g_max_exec_mem_size = s_exec_mem_size; | |
| 156 } | |
| 157 | |
| 158 // http://crbug.com/16114 | 95 // http://crbug.com/16114 |
| 159 // Enforces providing a valid device context in NPWindow, so that NPP_SetWindow | 96 // Enforces providing a valid device context in NPWindow, so that NPP_SetWindow |
| 160 // is never called with NPNWindoTypeDrawable and NPWindow set to NULL. | 97 // is never called with NPNWindoTypeDrawable and NPWindow set to NULL. |
| 161 // Doing so allows removing NPP_SetWindow call during painting a windowless | 98 // Doing so allows removing NPP_SetWindow call during painting a windowless |
| 162 // plugin, which otherwise could trigger layout change while painting by | 99 // plugin, which otherwise could trigger layout change while painting by |
| 163 // invoking NPN_Evaluate. Which would cause bad, bad crashes. Bad crashes. | 100 // invoking NPN_Evaluate. Which would cause bad, bad crashes. Bad crashes. |
| 164 // TODO(dglazkov): If this approach doesn't produce regressions, move class to | 101 // TODO(dglazkov): If this approach doesn't produce regressions, move class to |
| 165 // webplugin_delegate_impl.h and implement for other platforms. | 102 // webplugin_delegate_impl.h and implement for other platforms. |
| 166 class DrawableContextEnforcer { | 103 class DrawableContextEnforcer { |
| 167 public: | 104 public: |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 int code, WPARAM wParam, LPARAM lParam) { | 267 int code, WPARAM wParam, LPARAM lParam) { |
| 331 if (code == HC_ACTION) { | 268 if (code == HC_ACTION) { |
| 332 MOUSEHOOKSTRUCT* hook_struct = reinterpret_cast<MOUSEHOOKSTRUCT*>(lParam); | 269 MOUSEHOOKSTRUCT* hook_struct = reinterpret_cast<MOUSEHOOKSTRUCT*>(lParam); |
| 333 if (hook_struct) | 270 if (hook_struct) |
| 334 HandleCaptureForMessage(hook_struct->hwnd, wParam); | 271 HandleCaptureForMessage(hook_struct->hwnd, wParam); |
| 335 } | 272 } |
| 336 | 273 |
| 337 return CallNextHookEx(NULL, code, wParam, lParam); | 274 return CallNextHookEx(NULL, code, wParam, lParam); |
| 338 } | 275 } |
| 339 | 276 |
| 340 // In addition to the key state we maintain, we also mask in the original | |
| 341 // return value. This is done because system keys (e.g. tab, enter, shift) | |
| 342 // and toggles (e.g. capslock, numlock) don't ever seem to be blocked. | |
| 343 SHORT WINAPI WebPluginDelegateImpl::GetKeyStatePatch(int vkey) { | |
| 344 if (GetSavedKeyState(vkey)) | |
| 345 return g_iat_orig_get_key_state(vkey) | 0x8000; | |
| 346 return g_iat_orig_get_key_state(vkey); | |
| 347 } | |
| 348 | |
| 349 // We need to track RX memory usage in plugins to prevent JIT spraying attacks. | |
| 350 // This is done by hooking VirtualProtect and VirtualFree. | |
| 351 BOOL WINAPI WebPluginDelegateImpl::VirtualProtectPatch(LPVOID address, | |
| 352 SIZE_T size, | |
| 353 DWORD new_protect, | |
| 354 PDWORD old_protect) { | |
| 355 if (g_iat_orig_virtual_protect(address, size, new_protect, old_protect)) { | |
| 356 bool is_exec = new_protect == kExecPageMask; | |
| 357 bool was_exec = *old_protect == kExecPageMask; | |
| 358 if (is_exec && !was_exec) { | |
| 359 UpdateExecMemSize(static_cast<intptr_t>(size)); | |
| 360 } else if (!is_exec && was_exec) { | |
| 361 UpdateExecMemSize(-(static_cast<intptr_t>(size))); | |
| 362 } | |
| 363 | |
| 364 return TRUE; | |
| 365 } | |
| 366 | |
| 367 return FALSE; | |
| 368 } | |
| 369 | |
| 370 BOOL WINAPI WebPluginDelegateImpl::VirtualFreePatch(LPVOID address, | |
| 371 SIZE_T size, | |
| 372 DWORD free_type) { | |
| 373 MEMORY_BASIC_INFORMATION mem_info; | |
| 374 if (::VirtualQuery(address, &mem_info, sizeof(mem_info))) { | |
| 375 size_t exec_size = 0; | |
| 376 void* base_address = mem_info.AllocationBase; | |
| 377 do { | |
| 378 if (mem_info.Protect == kExecPageMask) | |
| 379 exec_size += mem_info.RegionSize; | |
| 380 BYTE* next = reinterpret_cast<BYTE*>(mem_info.BaseAddress) + | |
| 381 mem_info.RegionSize; | |
| 382 if (!::VirtualQuery(next, &mem_info, sizeof(mem_info))) | |
| 383 break; | |
| 384 } while (base_address == mem_info.AllocationBase); | |
| 385 | |
| 386 if (exec_size) | |
| 387 UpdateExecMemSize(-(static_cast<intptr_t>(exec_size))); | |
| 388 } | |
| 389 | |
| 390 return g_iat_orig_virtual_free(address, size, free_type); | |
| 391 } | |
| 392 | |
| 393 WebPluginDelegateImpl::WebPluginDelegateImpl( | 277 WebPluginDelegateImpl::WebPluginDelegateImpl( |
| 394 gfx::PluginWindowHandle containing_view, | 278 gfx::PluginWindowHandle containing_view, |
| 395 PluginInstance* instance) | 279 PluginInstance* instance) |
| 396 : parent_(containing_view), | 280 : parent_(containing_view), |
| 397 instance_(instance), | 281 instance_(instance), |
| 398 quirks_(0), | 282 quirks_(0), |
| 399 plugin_(NULL), | 283 plugin_(NULL), |
| 400 windowless_(false), | 284 windowless_(false), |
| 401 windowed_handle_(NULL), | 285 windowed_handle_(NULL), |
| 402 windowed_did_set_window_(false), | 286 windowed_did_set_window_(false), |
| 403 plugin_wnd_proc_(NULL), | 287 plugin_wnd_proc_(NULL), |
| 404 last_message_(0), | 288 last_message_(0), |
| 405 is_calling_wndproc(false), | 289 is_calling_wndproc(false), |
| 406 dummy_window_for_activation_(NULL), | 290 dummy_window_for_activation_(NULL), |
| 407 parent_proxy_window_(NULL), | |
| 408 handle_event_message_filter_hook_(NULL), | 291 handle_event_message_filter_hook_(NULL), |
| 409 handle_event_pump_messages_event_(NULL), | 292 handle_event_pump_messages_event_(NULL), |
| 410 user_gesture_message_posted_(false), | 293 user_gesture_message_posted_(false), |
| 411 ALLOW_THIS_IN_INITIALIZER_LIST(user_gesture_msg_factory_(this)), | 294 ALLOW_THIS_IN_INITIALIZER_LIST(user_gesture_msg_factory_(this)), |
| 412 handle_event_depth_(0), | 295 handle_event_depth_(0), |
| 413 mouse_hook_(NULL), | 296 mouse_hook_(NULL), |
| 414 first_set_window_call_(true), | 297 first_set_window_call_(true), |
| 415 plugin_has_focus_(false), | 298 plugin_has_focus_(false), |
| 416 has_webkit_focus_(false), | 299 has_webkit_focus_(false), |
| 417 containing_view_has_focus_(true), | 300 containing_view_has_focus_(true), |
| 418 creation_succeeded_(false) { | 301 creation_succeeded_(false) { |
| 419 memset(&window_, 0, sizeof(window_)); | 302 memset(&window_, 0, sizeof(window_)); |
| 420 | 303 |
| 421 const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info(); | 304 const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info(); |
| 422 std::wstring filename = | 305 std::wstring filename = |
| 423 StringToLowerASCII(plugin_info.path.BaseName().value()); | 306 StringToLowerASCII(plugin_info.path.BaseName().value()); |
| 424 | 307 |
| 425 if (instance_->mime_type() == kFlashPluginSwfMimeType || | 308 if (instance_->mime_type() == kFlashPluginSwfMimeType || |
| 426 filename == kFlashPlugin) { | 309 filename == kFlashPlugin) { |
| 427 // Flash only requests windowless plugins if we return a Mozilla user | 310 // Flash only requests windowless plugins if we return a Mozilla user |
| 428 // agent. | 311 // agent. |
| 429 instance_->set_use_mozilla_user_agent(); | 312 instance_->set_use_mozilla_user_agent(); |
| 430 quirks_ |= PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE; | 313 quirks_ |= PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE; |
| 431 quirks_ |= PLUGIN_QUIRK_PATCH_SETCURSOR; | 314 quirks_ |= PLUGIN_QUIRK_PATCH_SETCURSOR; |
| 432 quirks_ |= PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS; | 315 quirks_ |= PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS; |
| 433 quirks_ |= PLUGIN_QUIRK_HANDLE_MOUSE_CAPTURE; | 316 quirks_ |= PLUGIN_QUIRK_HANDLE_MOUSE_CAPTURE; |
| 434 if (filename == kBuiltinFlashPlugin && | |
| 435 base::win::GetVersion() >= base::win::VERSION_VISTA) { | |
| 436 quirks_ |= PLUGIN_QUIRK_REPARENT_IN_BROWSER | | |
| 437 PLUGIN_QUIRK_PATCH_GETKEYSTATE | | |
| 438 PLUGIN_QUIRK_PATCH_VM_API; | |
| 439 } | |
| 440 quirks_ |= PLUGIN_QUIRK_EMULATE_IME; | 317 quirks_ |= PLUGIN_QUIRK_EMULATE_IME; |
| 441 } else if (filename == kAcrobatReaderPlugin) { | 318 } else if (filename == kAcrobatReaderPlugin) { |
| 442 // Check for the version number above or equal 9. | 319 // Check for the version number above or equal 9. |
| 443 int major_version = GetPluginMajorVersion(plugin_info); | 320 int major_version = GetPluginMajorVersion(plugin_info); |
| 444 if (major_version >= 9) { | 321 if (major_version >= 9) { |
| 445 quirks_ |= PLUGIN_QUIRK_DIE_AFTER_UNLOAD; | 322 quirks_ |= PLUGIN_QUIRK_DIE_AFTER_UNLOAD; |
| 446 // 9.2 needs this. | 323 // 9.2 needs this. |
| 447 quirks_ |= PLUGIN_QUIRK_SETWINDOW_TWICE; | 324 quirks_ |= PLUGIN_QUIRK_SETWINDOW_TWICE; |
| 448 } | 325 } |
| 449 quirks_ |= PLUGIN_QUIRK_BLOCK_NONSTANDARD_GETURL_REQUESTS; | 326 quirks_ |= PLUGIN_QUIRK_BLOCK_NONSTANDARD_GETURL_REQUESTS; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 486 } else if (plugin_info.name.find(L"DivX Web Player") != | 363 } else if (plugin_info.name.find(L"DivX Web Player") != |
| 487 std::wstring::npos) { | 364 std::wstring::npos) { |
| 488 // The divx plugin sets its size on the first NPP_SetWindow call and never | 365 // The divx plugin sets its size on the first NPP_SetWindow call and never |
| 489 // updates its size. We should call the underlying NPP_SetWindow only when | 366 // updates its size. We should call the underlying NPP_SetWindow only when |
| 490 // we have the correct size. | 367 // we have the correct size. |
| 491 quirks_ |= PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL; | 368 quirks_ |= PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL; |
| 492 } | 369 } |
| 493 } | 370 } |
| 494 | 371 |
| 495 WebPluginDelegateImpl::~WebPluginDelegateImpl() { | 372 WebPluginDelegateImpl::~WebPluginDelegateImpl() { |
| 496 if (::IsWindow(dummy_window_for_activation_)) { | 373 if (::IsWindow(dummy_window_for_activation_)) |
| 497 // Sandboxed Flash stacks two dummy windows to prevent UIPI failures | 374 ::DestroyWindow(dummy_window_for_activation_); |
| 498 if (::IsWindow(parent_proxy_window_)) | |
| 499 ::DestroyWindow(parent_proxy_window_); | |
| 500 else | |
| 501 ::DestroyWindow(dummy_window_for_activation_); | |
| 502 } | |
| 503 | 375 |
| 504 DestroyInstance(); | 376 DestroyInstance(); |
| 505 | 377 |
| 506 if (!windowless_) | 378 if (!windowless_) |
| 507 WindowedDestroyWindow(); | 379 WindowedDestroyWindow(); |
| 508 | 380 |
| 509 if (handle_event_pump_messages_event_) { | 381 if (handle_event_pump_messages_event_) { |
| 510 CloseHandle(handle_event_pump_messages_event_); | 382 CloseHandle(handle_event_pump_messages_event_); |
| 511 } | 383 } |
| 512 } | 384 } |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 // and use them to retrieve IME data. We add a patch to this function so we | 454 // and use them to retrieve IME data. We add a patch to this function so we |
| 583 // can dispatch these IMM32 calls to the WebPluginIMEWin class, which emulates | 455 // can dispatch these IMM32 calls to the WebPluginIMEWin class, which emulates |
| 584 // IMM32 functions for Flash. | 456 // IMM32 functions for Flash. |
| 585 if (!g_iat_patch_get_proc_address.Pointer()->is_patched() && | 457 if (!g_iat_patch_get_proc_address.Pointer()->is_patched() && |
| 586 (quirks_ & PLUGIN_QUIRK_EMULATE_IME)) { | 458 (quirks_ & PLUGIN_QUIRK_EMULATE_IME)) { |
| 587 g_iat_patch_get_proc_address.Pointer()->Patch( | 459 g_iat_patch_get_proc_address.Pointer()->Patch( |
| 588 GetPluginPath().value().c_str(), "kernel32.dll", "GetProcAddress", | 460 GetPluginPath().value().c_str(), "kernel32.dll", "GetProcAddress", |
| 589 GetProcAddressPatch); | 461 GetProcAddressPatch); |
| 590 } | 462 } |
| 591 | 463 |
| 592 // Under UIPI the key state does not get forwarded properly to the child | |
| 593 // plugin window. So, instead we track the key state manually and intercept | |
| 594 // GetKeyState. | |
| 595 if ((quirks_ & PLUGIN_QUIRK_PATCH_GETKEYSTATE) && | |
| 596 !g_iat_patch_get_key_state.Pointer()->is_patched()) { | |
| 597 g_iat_orig_get_key_state = ::GetKeyState; | |
| 598 g_iat_patch_get_key_state.Pointer()->Patch( | |
| 599 L"gcswf32.dll", "user32.dll", "GetKeyState", | |
| 600 WebPluginDelegateImpl::GetKeyStatePatch); | |
| 601 } | |
| 602 | |
| 603 // Hook the VM calls so we can track the amount of executable memory being | |
| 604 // allocated by Flash (and potentially other plugins). | |
| 605 if (quirks_ & PLUGIN_QUIRK_PATCH_VM_API) { | |
| 606 if (!g_exec_mem_lock.get()) | |
| 607 g_exec_mem_lock.reset(new base::Lock()); | |
| 608 | |
| 609 if (!g_iat_patch_virtual_protect.Pointer()->is_patched()) { | |
| 610 g_iat_orig_virtual_protect = ::VirtualProtect; | |
| 611 g_iat_patch_virtual_protect.Pointer()->Patch( | |
| 612 L"gcswf32.dll", "kernel32.dll", "VirtualProtect", | |
| 613 WebPluginDelegateImpl::VirtualProtectPatch); | |
| 614 } | |
| 615 if (!g_iat_patch_virtual_free.Pointer()->is_patched()) { | |
| 616 g_iat_orig_virtual_free = ::VirtualFree; | |
| 617 g_iat_patch_virtual_free.Pointer()->Patch( | |
| 618 L"gcswf32.dll", "kernel32.dll", "VirtualFree", | |
| 619 WebPluginDelegateImpl::VirtualFreePatch); | |
| 620 } | |
| 621 } | |
| 622 | |
| 623 return true; | 464 return true; |
| 624 } | 465 } |
| 625 | 466 |
| 626 void WebPluginDelegateImpl::PlatformDestroyInstance() { | 467 void WebPluginDelegateImpl::PlatformDestroyInstance() { |
| 627 if (!instance_->plugin_lib()) | 468 if (!instance_->plugin_lib()) |
| 628 return; | 469 return; |
| 629 | 470 |
| 630 // Unpatch if this is the last plugin instance. | 471 // Unpatch if this is the last plugin instance. |
| 631 if (instance_->plugin_lib()->instance_count() != 1) | 472 if (instance_->plugin_lib()->instance_count() != 1) |
| 632 return; | 473 return; |
| 633 | 474 |
| 634 // Pass back the stats for max executable memory. | |
| 635 if (quirks_ & PLUGIN_QUIRK_PATCH_VM_API) { | |
| 636 plugin_->ReportExecutableMemory(g_max_exec_mem_size); | |
| 637 g_max_exec_mem_size = 0; | |
| 638 } | |
| 639 | |
| 640 if (g_iat_patch_set_cursor.Pointer()->is_patched()) | 475 if (g_iat_patch_set_cursor.Pointer()->is_patched()) |
| 641 g_iat_patch_set_cursor.Pointer()->Unpatch(); | 476 g_iat_patch_set_cursor.Pointer()->Unpatch(); |
| 642 | 477 |
| 643 if (g_iat_patch_track_popup_menu.Pointer()->is_patched()) | 478 if (g_iat_patch_track_popup_menu.Pointer()->is_patched()) |
| 644 g_iat_patch_track_popup_menu.Pointer()->Unpatch(); | 479 g_iat_patch_track_popup_menu.Pointer()->Unpatch(); |
| 645 | 480 |
| 646 if (g_iat_patch_reg_enum_key_ex_w.Pointer()->is_patched()) | 481 if (g_iat_patch_reg_enum_key_ex_w.Pointer()->is_patched()) |
| 647 g_iat_patch_reg_enum_key_ex_w.Pointer()->Unpatch(); | 482 g_iat_patch_reg_enum_key_ex_w.Pointer()->Unpatch(); |
| 648 | 483 |
| 649 if (mouse_hook_) { | 484 if (mouse_hook_) { |
| 650 UnhookWindowsHookEx(mouse_hook_); | 485 UnhookWindowsHookEx(mouse_hook_); |
| 651 mouse_hook_ = NULL; | 486 mouse_hook_ = NULL; |
| 652 } | 487 } |
| 653 } | 488 } |
| 654 | 489 |
| 655 void WebPluginDelegateImpl::Paint(WebKit::WebCanvas* canvas, | 490 void WebPluginDelegateImpl::Paint(WebKit::WebCanvas* canvas, |
| 656 const gfx::Rect& rect) { | 491 const gfx::Rect& rect) { |
| 657 if (windowless_ && skia::SupportsPlatformPaint(canvas)) { | 492 if (windowless_ && skia::SupportsPlatformPaint(canvas)) { |
| 658 skia::ScopedPlatformPaint scoped_platform_paint(canvas); | 493 skia::ScopedPlatformPaint scoped_platform_paint(canvas); |
| 659 HDC hdc = scoped_platform_paint.GetPlatformSurface(); | 494 HDC hdc = scoped_platform_paint.GetPlatformSurface(); |
| 660 WindowlessPaint(hdc, rect); | 495 WindowlessPaint(hdc, rect); |
| 661 } | 496 } |
| 662 } | 497 } |
| 663 | 498 |
| 664 bool WebPluginDelegateImpl::WindowedCreatePlugin() { | 499 bool WebPluginDelegateImpl::WindowedCreatePlugin() { |
| 665 DCHECK(!windowed_handle_); | 500 DCHECK(!windowed_handle_); |
| 666 | 501 |
| 667 RegisterNativeWindowClass(); | 502 RegisterNativeWindowClass(); |
| 668 | 503 |
| 669 // UIPI requires reparenting in the (medium-integrity) browser process. | |
| 670 bool reparent_in_browser = (quirks_ & PLUGIN_QUIRK_REPARENT_IN_BROWSER) != 0; | |
| 671 | |
| 672 // The window will be sized and shown later. | 504 // The window will be sized and shown later. |
| 673 windowed_handle_ = CreateWindowEx( | 505 windowed_handle_ = CreateWindowEx( |
| 674 WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, | 506 WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, |
| 675 kNativeWindowClassName, | 507 kNativeWindowClassName, |
| 676 0, | 508 0, |
| 677 WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, | 509 WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, |
| 678 0, | 510 0, |
| 679 0, | 511 0, |
| 680 0, | 512 0, |
| 681 0, | 513 0, |
| 682 reparent_in_browser ? NULL : parent_, | 514 parent_, |
| 683 0, | 515 0, |
| 684 GetModuleHandle(NULL), | 516 GetModuleHandle(NULL), |
| 685 0); | 517 0); |
| 686 if (windowed_handle_ == 0) | 518 if (windowed_handle_ == 0) |
| 687 return false; | 519 return false; |
| 688 | 520 |
| 689 if (reparent_in_browser) { | 521 if (IsWindow(parent_)) { |
| 690 plugin_->ReparentPluginWindow(windowed_handle_, parent_); | |
| 691 } else if (IsWindow(parent_)) { | |
| 692 // This is a tricky workaround for Issue 2673 in chromium "Flash: IME not | 522 // This is a tricky workaround for Issue 2673 in chromium "Flash: IME not |
| 693 // available". To use IMEs in this window, we have to make Windows attach | 523 // available". To use IMEs in this window, we have to make Windows attach |
| 694 // IMEs to this window (i.e. load IME DLLs, attach them to this process, | 524 // IMEs to this window (i.e. load IME DLLs, attach them to this process, |
| 695 // and add their message hooks to this window). Windows attaches IMEs while | 525 // and add their message hooks to this window). Windows attaches IMEs while |
| 696 // this process creates a top-level window. On the other hand, to layout | 526 // this process creates a top-level window. On the other hand, to layout |
| 697 // this window correctly in the given parent window (RenderWidgetHostHWND), | 527 // this window correctly in the given parent window (RenderWidgetHostHWND), |
| 698 // this window should be a child window of the parent window. | 528 // this window should be a child window of the parent window. |
| 699 // To satisfy both of the above conditions, this code once creates a | 529 // To satisfy both of the above conditions, this code once creates a |
| 700 // top-level window and change it to a child window of the parent window. | 530 // top-level window and change it to a child window of the parent window. |
| 701 SetWindowLongPtr(windowed_handle_, GWL_STYLE, | 531 SetWindowLongPtr(windowed_handle_, GWL_STYLE, |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 903 DCHECK(old_flash_proc); | 733 DCHECK(old_flash_proc); |
| 904 g_window_handle_proc_map.Get()[window] = old_flash_proc; | 734 g_window_handle_proc_map.Get()[window] = old_flash_proc; |
| 905 } | 735 } |
| 906 | 736 |
| 907 return TRUE; | 737 return TRUE; |
| 908 } | 738 } |
| 909 | 739 |
| 910 bool WebPluginDelegateImpl::CreateDummyWindowForActivation() { | 740 bool WebPluginDelegateImpl::CreateDummyWindowForActivation() { |
| 911 DCHECK(!dummy_window_for_activation_); | 741 DCHECK(!dummy_window_for_activation_); |
| 912 | 742 |
| 913 // Built-in Flash runs with UIPI, but in windowless mode Flash sometimes | |
| 914 // tries to attach windows to the parent (which fails under UIPI). To make | |
| 915 // it work we add an extra dummy parent in the low-integrity process. | |
| 916 if (quirks_ & PLUGIN_QUIRK_REPARENT_IN_BROWSER) { | |
| 917 parent_proxy_window_ = CreateWindowEx( | |
| 918 0, | |
| 919 L"Static", | |
| 920 kDummyActivationWindowName, | |
| 921 WS_POPUP, | |
| 922 0, | |
| 923 0, | |
| 924 0, | |
| 925 0, | |
| 926 0, | |
| 927 0, | |
| 928 GetModuleHandle(NULL), | |
| 929 0); | |
| 930 | |
| 931 if (parent_proxy_window_ == 0) | |
| 932 return false; | |
| 933 plugin_->ReparentPluginWindow(parent_proxy_window_, parent_); | |
| 934 } | |
| 935 | |
| 936 dummy_window_for_activation_ = CreateWindowEx( | 743 dummy_window_for_activation_ = CreateWindowEx( |
| 937 0, | 744 0, |
| 938 L"Static", | 745 L"Static", |
| 939 kDummyActivationWindowName, | 746 kDummyActivationWindowName, |
| 940 WS_CHILD, | 747 WS_CHILD, |
| 941 0, | 748 0, |
| 942 0, | 749 0, |
| 943 0, | 750 0, |
| 944 0, | 751 0, |
| 945 parent_proxy_window_ ? parent_proxy_window_ : parent_, | 752 parent_, |
| 946 0, | 753 0, |
| 947 GetModuleHandle(NULL), | 754 GetModuleHandle(NULL), |
| 948 0); | 755 0); |
| 949 | 756 |
| 950 if (dummy_window_for_activation_ == 0) | 757 if (dummy_window_for_activation_ == 0) |
| 951 return false; | 758 return false; |
| 952 | 759 |
| 953 // Flash creates background windows which use excessive CPU in our | 760 // Flash creates background windows which use excessive CPU in our |
| 954 // environment; we wrap these windows and throttle them so that they don't | 761 // environment; we wrap these windows and throttle them so that they don't |
| 955 // get out of hand. | 762 // get out of hand. |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1126 // Flash may flood the message queue with WM_USER+1 message causing 100% CPU | 933 // Flash may flood the message queue with WM_USER+1 message causing 100% CPU |
| 1127 // usage. See https://bugzilla.mozilla.org/show_bug.cgi?id=132759. We | 934 // usage. See https://bugzilla.mozilla.org/show_bug.cgi?id=132759. We |
| 1128 // prevent this by throttling the messages. | 935 // prevent this by throttling the messages. |
| 1129 if (message == WM_USER + 1 && | 936 if (message == WM_USER + 1 && |
| 1130 delegate->GetQuirks() & PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE) { | 937 delegate->GetQuirks() & PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE) { |
| 1131 WebPluginDelegateImpl::ThrottleMessage(delegate->plugin_wnd_proc_, hwnd, | 938 WebPluginDelegateImpl::ThrottleMessage(delegate->plugin_wnd_proc_, hwnd, |
| 1132 message, wparam, lparam); | 939 message, wparam, lparam); |
| 1133 return FALSE; | 940 return FALSE; |
| 1134 } | 941 } |
| 1135 | 942 |
| 1136 // Track the keystate to work around a UIPI issue. | |
| 1137 if (delegate->GetQuirks() & PLUGIN_QUIRK_PATCH_GETKEYSTATE) { | |
| 1138 switch (message) { | |
| 1139 case WM_KEYDOWN: | |
| 1140 SetSavedKeyState(wparam); | |
| 1141 break; | |
| 1142 | |
| 1143 case WM_KEYUP: | |
| 1144 UnsetSavedKeyState(wparam); | |
| 1145 break; | |
| 1146 | |
| 1147 // Clear out the saved keystate whenever the Flash thread loses focus. | |
| 1148 case WM_KILLFOCUS: | |
| 1149 case WM_SETFOCUS: | |
| 1150 if (::GetCurrentThreadId() != ::GetWindowThreadProcessId( | |
| 1151 reinterpret_cast<HWND>(wparam), NULL)) { | |
| 1152 ClearSavedKeyState(); | |
| 1153 } | |
| 1154 break; | |
| 1155 | |
| 1156 default: | |
| 1157 break; | |
| 1158 } | |
| 1159 } | |
| 1160 | |
| 1161 LRESULT result; | 943 LRESULT result; |
| 1162 uint32 old_message = delegate->last_message_; | 944 uint32 old_message = delegate->last_message_; |
| 1163 delegate->last_message_ = message; | 945 delegate->last_message_ = message; |
| 1164 | 946 |
| 1165 static UINT custom_msg = RegisterWindowMessage(kPaintMessageName); | 947 static UINT custom_msg = RegisterWindowMessage(kPaintMessageName); |
| 1166 if (message == custom_msg) { | 948 if (message == custom_msg) { |
| 1167 // Get the invalid rect which is in screen coordinates and convert to | 949 // Get the invalid rect which is in screen coordinates and convert to |
| 1168 // window coordinates. | 950 // window coordinates. |
| 1169 gfx::Rect invalid_rect; | 951 gfx::Rect invalid_rect; |
| 1170 invalid_rect.set_x(wparam >> 16); | 952 invalid_rect.set_x(wparam >> 16); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1317 } | 1099 } |
| 1318 | 1100 |
| 1319 bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) { | 1101 bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) { |
| 1320 DCHECK(instance()->windowless()); | 1102 DCHECK(instance()->windowless()); |
| 1321 | 1103 |
| 1322 NPEvent focus_event; | 1104 NPEvent focus_event; |
| 1323 focus_event.event = focused ? WM_SETFOCUS : WM_KILLFOCUS; | 1105 focus_event.event = focused ? WM_SETFOCUS : WM_KILLFOCUS; |
| 1324 focus_event.wParam = 0; | 1106 focus_event.wParam = 0; |
| 1325 focus_event.lParam = 0; | 1107 focus_event.lParam = 0; |
| 1326 | 1108 |
| 1327 if (GetQuirks() & PLUGIN_QUIRK_PATCH_GETKEYSTATE) | |
| 1328 ClearSavedKeyState(); | |
| 1329 | |
| 1330 instance()->NPP_HandleEvent(&focus_event); | 1109 instance()->NPP_HandleEvent(&focus_event); |
| 1331 return true; | 1110 return true; |
| 1332 } | 1111 } |
| 1333 | 1112 |
| 1334 static bool NPEventFromWebMouseEvent(const WebMouseEvent& event, | 1113 static bool NPEventFromWebMouseEvent(const WebMouseEvent& event, |
| 1335 NPEvent* np_event) { | 1114 NPEvent* np_event) { |
| 1336 np_event->lParam = static_cast<uint32>(MAKELPARAM(event.windowX, | 1115 np_event->lParam = static_cast<uint32>(MAKELPARAM(event.windowX, |
| 1337 event.windowY)); | 1116 event.windowY)); |
| 1338 np_event->wParam = 0; | 1117 np_event->wParam = 0; |
| 1339 | 1118 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1439 | 1218 |
| 1440 bool WebPluginDelegateImpl::PlatformHandleInputEvent( | 1219 bool WebPluginDelegateImpl::PlatformHandleInputEvent( |
| 1441 const WebInputEvent& event, WebCursorInfo* cursor_info) { | 1220 const WebInputEvent& event, WebCursorInfo* cursor_info) { |
| 1442 DCHECK(cursor_info != NULL); | 1221 DCHECK(cursor_info != NULL); |
| 1443 | 1222 |
| 1444 NPEvent np_event; | 1223 NPEvent np_event; |
| 1445 if (!NPEventFromWebInputEvent(event, &np_event)) { | 1224 if (!NPEventFromWebInputEvent(event, &np_event)) { |
| 1446 return false; | 1225 return false; |
| 1447 } | 1226 } |
| 1448 | 1227 |
| 1449 if (GetQuirks() & PLUGIN_QUIRK_PATCH_GETKEYSTATE) { | |
| 1450 if (np_event.event == WM_KEYDOWN) | |
| 1451 SetSavedKeyState(np_event.wParam); | |
| 1452 else if (np_event.event == WM_KEYUP) | |
| 1453 UnsetSavedKeyState(np_event.wParam); | |
| 1454 } | |
| 1455 | |
| 1456 // Allow this plug-in to access this IME emulator through IMM32 API while the | 1228 // Allow this plug-in to access this IME emulator through IMM32 API while the |
| 1457 // plug-in is processing this event. | 1229 // plug-in is processing this event. |
| 1458 if (GetQuirks() & PLUGIN_QUIRK_EMULATE_IME) { | 1230 if (GetQuirks() & PLUGIN_QUIRK_EMULATE_IME) { |
| 1459 if (!plugin_ime_.get()) | 1231 if (!plugin_ime_.get()) |
| 1460 plugin_ime_.reset(new WebPluginIMEWin); | 1232 plugin_ime_.reset(new WebPluginIMEWin); |
| 1461 } | 1233 } |
| 1462 WebPluginIMEWin::ScopedLock lock(plugin_ime_.get()); | 1234 WebPluginIMEWin::ScopedLock lock(plugin_ime_.get()); |
| 1463 | 1235 |
| 1464 HWND last_focus_window = NULL; | 1236 HWND last_focus_window = NULL; |
| 1465 | 1237 |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1696 ::ReleaseCapture(); | 1468 ::ReleaseCapture(); |
| 1697 break; | 1469 break; |
| 1698 | 1470 |
| 1699 default: | 1471 default: |
| 1700 break; | 1472 break; |
| 1701 } | 1473 } |
| 1702 } | 1474 } |
| 1703 | 1475 |
| 1704 } // namespace npapi | 1476 } // namespace npapi |
| 1705 } // namespace webkit | 1477 } // namespace webkit |
| OLD | NEW |