diff options
author | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-09 01:20:38 +0000 |
---|---|---|
committer | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-09 01:20:38 +0000 |
commit | cf4e5eb1df0fcbf192584b61e83e0b85cf23a1cf (patch) | |
tree | bce3c121d9679666d8acdf73cb082a684cf491e4 /webkit/glue/plugins | |
parent | 710e056bd5005f8d0f9f9d5f4b8623f9c9dd7004 (diff) | |
download | chromium_src-cf4e5eb1df0fcbf192584b61e83e0b85cf23a1cf.zip chromium_src-cf4e5eb1df0fcbf192584b61e83e0b85cf23a1cf.tar.gz chromium_src-cf4e5eb1df0fcbf192584b61e83e0b85cf23a1cf.tar.bz2 |
Add support for custom cursors set by windowless plugins. Windowless plugins typically set the cursor in NPP_HandleEvent for WM_MOUSEMOVE.The current implementation looks for the cursor type and if the typedoes not match predefinedcursor types defaults to the pointer cursor.
The fixes are as below:-
1. Marshal the HCURSOR after copying it to ensure that it
remains valid. This works as a HCURSOR is a user object
and can be used across processes. Ideally we would
like to convert it to a skia bitmap but there are issues
with converting monochrome cursors.
2. Added support for marshaling platform specific data in
the webcursor Serialize/Deserialize functions. This is in
the form of functions like InitPlatformData,
SerializePlatformData, DeserializePlatformData, etc.
which are stubbed out for the other platforms.
3. Mimic webkit windowless plugin behavior where it sets a
flag to ignore the next setCursor after HandleEvent of
WM_MOUSEMOVE. If we don't do this the cursor keeps
changing between a pointerCursor and the cursor set by
the plugin which also causes flicker.
4. Fixed the WebCursor::IsEqual function to ensure that it
checks all fields for equality.
5. The browser(RenderWidgetHostViewWin) now maintains a
WebCursor instance representing the current cursor. Any
cursor updates received from the renderer update the
current cursor member maintained by the browser.
6. We intercept the SetCursor API for windowless plugins
like Flash and Silverlight and remember the cursor being
set. We don't invoke the original API as the browser UI
thread would do it anyways. This fixes the annoying
cursor flicker caused by the windowless flash plugin
instance constantly setting the cursor even when the tab
is not visible.
This fixes bug http://code.google.com/p/chromium/issues/detail?id=3800.
Review URL: http://codereview.chromium.org/15088
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@7798 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/plugins')
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.cc | 82 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.h | 17 |
2 files changed, 77 insertions, 22 deletions
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.cc b/webkit/glue/plugins/webplugin_delegate_impl.cc index 655a37a..364ae10 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.cc +++ b/webkit/glue/plugins/webplugin_delegate_impl.cc @@ -47,8 +47,8 @@ std::list<MSG> WebPluginDelegateImpl::throttle_queue_; WebPluginDelegateImpl* WebPluginDelegateImpl::current_plugin_instance_ = NULL; -bool WebPluginDelegateImpl::track_popup_menu_patched_ = false; -iat_patch::IATPatchFunction WebPluginDelegateImpl::iat_patch_helper_; +iat_patch::IATPatchFunction WebPluginDelegateImpl::iat_patch_track_popup_menu_; +iat_patch::IATPatchFunction WebPluginDelegateImpl::iat_patch_set_cursor_; WebPluginDelegateImpl* WebPluginDelegateImpl::Create( const FilePath& filename, @@ -153,6 +153,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( // agent. instance_->set_use_mozilla_user_agent(); quirks_ |= PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE; + quirks_ |= PLUGIN_QUIRK_PATCH_SETCURSOR; } else if (filename == L"nppdf32.dll") { // Check for the version number above or equal 9. std::vector<std::wstring> version; @@ -181,6 +182,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( // Explanation for this quirk can be found in // WebPluginDelegateImpl::Initialize. quirks_ |= PLUGIN_QUIRK_PATCH_TRACKPOPUP_MENU; + quirks_ |= PLUGIN_QUIRK_PATCH_SETCURSOR; } plugin_module_handle_ = ::GetModuleHandle(filename.c_str()); @@ -260,12 +262,24 @@ bool WebPluginDelegateImpl::Initialize(const GURL& url, // lives on the browser thread. Our workaround is to intercept the // TrackPopupMenu API for Silverlight and replace the window handle // with the dummy activation window. - if (windowless_ && !track_popup_menu_patched_ && + if (windowless_ && !iat_patch_track_popup_menu_.is_patched() && (quirks_ & PLUGIN_QUIRK_PATCH_TRACKPOPUP_MENU)) { - iat_patch_helper_.Patch(plugin_module_handle_, "user32.dll", - "TrackPopupMenu", - WebPluginDelegateImpl::TrackPopupMenuPatch); - track_popup_menu_patched_ = true; + iat_patch_track_popup_menu_.Patch( + plugin_module_handle_, "user32.dll", "TrackPopupMenu", + WebPluginDelegateImpl::TrackPopupMenuPatch); + } + + // Windowless plugins can set cursors by calling the SetCursor API. This + // works because the thread inputs of the browser UI thread and the plugin + // thread are attached. We intercept the SetCursor API for windowless plugins + // and remember the cursor being set. This is shipped over to the browser + // in the HandleEvent call, which ensures that the cursor does not change + // when a windowless plugin instance changes the cursor in a background tab. + if (windowless_ && !iat_patch_set_cursor_.is_patched() && + (quirks_ & PLUGIN_QUIRK_PATCH_SETCURSOR)) { + iat_patch_set_cursor_.Patch(plugin_module_handle_, "user32.dll", + "SetCursor", + WebPluginDelegateImpl::SetCursorPatch); } return true; } @@ -287,6 +301,19 @@ void WebPluginDelegateImpl::DestroyInstance() { instance_->set_web_plugin(NULL); + if (instance_->plugin_lib()) { + // Unpatch if this is the last plugin instance. + if (instance_->plugin_lib()->instance_count() == 1) { + if (iat_patch_set_cursor_.is_patched()) { + iat_patch_set_cursor_.Unpatch(); + } + + if (iat_patch_track_popup_menu_.is_patched()) { + iat_patch_track_popup_menu_.Unpatch(); + } + } + } + instance_ = 0; } } @@ -801,6 +828,8 @@ LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc( return TRUE; } + current_plugin_instance_ = delegate; + switch (message) { case WM_NCDESTROY: { RemoveProp(hwnd, kWebPluginDelegateProperty); @@ -818,6 +847,7 @@ LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc( if (delegate->quirks() & PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE) { WebPluginDelegateImpl::ThrottleMessage(delegate->plugin_wnd_proc_, hwnd, message, wparam, lparam); + current_plugin_instance_ = NULL; return FALSE; } break; @@ -844,6 +874,7 @@ LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc( LRESULT result = CallWindowProc(delegate->plugin_wnd_proc_, hwnd, message, wparam, lparam); delegate->is_calling_wndproc = false; + current_plugin_instance_ = NULL; return result; } @@ -998,12 +1029,11 @@ bool WebPluginDelegateImpl::HandleEvent(NPEvent* event, bool ret = instance()->NPP_HandleEvent(event) != 0; - // Snag a reference to the current cursor ASAP in case the plugin modified - // it. There is a nasty race condition here with the multiprocess browser - // as someone might be setting the cursor in the main process as well. - HCURSOR last_cursor; - if (WM_MOUSEMOVE == event->event) { - last_cursor = ::GetCursor(); + if (event->event == WM_MOUSEMOVE) { + // Snag a reference to the current cursor ASAP in case the plugin modified + // it. There is a nasty race condition here with the multiprocess browser + // as someone might be setting the cursor in the main process as well. + *cursor = current_windowless_cursor_; } if (pop_user_gesture) { @@ -1032,10 +1062,6 @@ bool WebPluginDelegateImpl::HandleEvent(NPEvent* event, ::SetFocus(prev_focus_window); } - if (WM_MOUSEMOVE == event->event) { - cursor->InitFromCursor(last_cursor); - } - return ret; } @@ -1124,3 +1150,25 @@ BOOL WINAPI WebPluginDelegateImpl::TrackPopupMenuPatch( } return TrackPopupMenu(menu, flags, x, y, reserved, window, rect); } + +HCURSOR WINAPI WebPluginDelegateImpl::SetCursorPatch(HCURSOR cursor) { + // The windowless flash plugin periodically calls SetCursor in a wndproc + // instantiated on the plugin thread. This causes annoying cursor flicker + // when the mouse is moved on a foreground tab, with a windowless plugin + // instance in a background tab. We just ignore the call here. + if (!current_plugin_instance_) + return GetCursor(); + + if (!current_plugin_instance_->windowless()) { + return SetCursor(cursor); + } + + // It is ok to pass NULL here to GetCursor as we are not looking for cursor + // types defined by Webkit. + HCURSOR previous_cursor = + current_plugin_instance_->current_windowless_cursor_.GetCursor(NULL); + + current_plugin_instance_->current_windowless_cursor_.InitFromExternalCursor( + cursor); + return previous_cursor; +} diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index a89189c..85c14dc 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -93,6 +93,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate { PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES = 16, PLUGIN_QUIRK_DIE_AFTER_UNLOAD = 32, PLUGIN_QUIRK_PATCH_TRACKPOPUP_MENU = 64, + PLUGIN_QUIRK_PATCH_SETCURSOR = 128, }; int quirks() { return quirks_; } @@ -264,11 +265,8 @@ class WebPluginDelegateImpl : public WebPluginDelegate { // The plugin module handle. HMODULE plugin_module_handle_; - // Indicates whether we IAT patched the TrackPopupMenu function. - static bool track_popup_menu_patched_; - - // Helper object for patching the import table of Silverlight. - static iat_patch::IATPatchFunction iat_patch_helper_; + // Helper object for patching the TrackPopupMenu API + static iat_patch::IATPatchFunction iat_patch_track_popup_menu_; // TrackPopupMenu interceptor. Parameters are the same as the Win32 function // TrackPopupMenu. @@ -276,6 +274,15 @@ class WebPluginDelegateImpl : public WebPluginDelegate { int y, int reserved, HWND window, const RECT* rect); + // SetCursor interceptor for windowless plugins. + static HCURSOR WINAPI SetCursorPatch(HCURSOR cursor); + + // Helper object for patching the SetCursor API + static iat_patch::IATPatchFunction iat_patch_set_cursor_; + + // Holds the current cursor set by the windowless plugin. + WebCursor current_windowless_cursor_; + DISALLOW_EVIL_CONSTRUCTORS(WebPluginDelegateImpl); }; |