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 | |
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')
-rw-r--r-- | webkit/glue/chrome_client_impl.cc | 16 | ||||
-rw-r--r-- | webkit/glue/chrome_client_impl.h | 3 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.cc | 82 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.h | 17 | ||||
-rw-r--r-- | webkit/glue/webcursor.cc | 57 | ||||
-rw-r--r-- | webkit/glue/webcursor.h | 59 | ||||
-rw-r--r-- | webkit/glue/webcursor_gtk.cc | 24 | ||||
-rw-r--r-- | webkit/glue/webcursor_mac.mm | 23 | ||||
-rw-r--r-- | webkit/glue/webcursor_win.cc | 83 | ||||
-rw-r--r-- | webkit/glue/webplugin_impl.cc | 9 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_webview_delegate.h | 8 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_webview_delegate_gtk.cc | 5 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_webview_delegate_win.cc | 16 |
13 files changed, 324 insertions, 78 deletions
diff --git a/webkit/glue/chrome_client_impl.cc b/webkit/glue/chrome_client_impl.cc index b7cc3ae..471eb14 100644 --- a/webkit/glue/chrome_client_impl.cc +++ b/webkit/glue/chrome_client_impl.cc @@ -57,7 +57,8 @@ ChromeClientImpl::ChromeClientImpl(WebViewImpl* webview) statusbar_visible_(true), scrollbars_visible_(true), menubar_visible_(true), - resizable_(true) { + resizable_(true), + ignore_next_set_cursor_(false) { } ChromeClientImpl::~ChromeClientImpl() { @@ -472,11 +473,24 @@ void ChromeClientImpl::popupOpened(WebCore::FramelessScrollView* popup_view, } void ChromeClientImpl::SetCursor(const WebCursor& cursor) { + if (ignore_next_set_cursor_) { + ignore_next_set_cursor_ = false; + return; + } + WebViewDelegate* d = webview_->delegate(); if (d) d->SetCursor(webview_, cursor); } +void ChromeClientImpl::SetCursorForPlugin(const WebCursor& cursor) { + SetCursor(cursor); + // Currently, Widget::setCursor is always called after this function in + // EventHandler.cpp and since we don't want that we set a flag indicating + // that the next SetCursor call is to be ignored. + ignore_next_set_cursor_ = true; +} + void ChromeClientImpl::enableSuddenTermination() { WebViewDelegate* d = webview_->delegate(); if (d) diff --git a/webkit/glue/chrome_client_impl.h b/webkit/glue/chrome_client_impl.h index af39a51..6e059eaa 100644 --- a/webkit/glue/chrome_client_impl.h +++ b/webkit/glue/chrome_client_impl.h @@ -120,6 +120,7 @@ public: bool focus_on_show); void SetCursor(const WebCursor& cursor); + void SetCursorForPlugin(const WebCursor& cursor); virtual void enableSuddenTermination(); virtual void disableSuddenTermination(); @@ -133,6 +134,8 @@ private: bool scrollbars_visible_; bool menubar_visible_; bool resizable_; + // Set to true if the next SetCursor is to be ignored. + bool ignore_next_set_cursor_; }; #endif // WEBKIT_GLUE_CHROME_CLIENT_IMPL_H__ 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); }; diff --git a/webkit/glue/webcursor.cc b/webkit/glue/webcursor.cc index 4c943c3..76673e5 100644 --- a/webkit/glue/webcursor.cc +++ b/webkit/glue/webcursor.cc @@ -14,6 +14,7 @@ WebCursor::WebCursor() : type_(WebCore::PlatformCursor::typePointer) { + InitPlatformData(); } WebCursor::WebCursor(const WebCore::PlatformCursor& platform_cursor) @@ -21,10 +22,31 @@ WebCursor::WebCursor(const WebCore::PlatformCursor& platform_cursor) hotspot_(platform_cursor.hotSpot().x(), platform_cursor.hotSpot().y()) { if (IsCustom()) SetCustomData(platform_cursor.customImage().get()); + + InitPlatformData(); +} + +WebCursor::~WebCursor() { + Clear(); +} + +WebCursor::WebCursor(const WebCursor& other) { + InitPlatformData(); + Copy(other); +} + +const WebCursor& WebCursor::operator=(const WebCursor& other) { + if (this == &other) + return *this; + + Clear(); + Copy(other); + return *this; } bool WebCursor::Deserialize(const Pickle* pickle, void** iter) { int type, hotspot_x, hotspot_y, size_x, size_y, data_len; + const char* data; // Leave |this| unmodified unless we are going to return success. @@ -48,7 +70,7 @@ bool WebCursor::Deserialize(const Pickle* pickle, void** iter) { memcpy(&custom_data_[0], data, data_len); } - return true; + return DeserializePlatformData(pickle, iter); } bool WebCursor::Serialize(Pickle* pickle) const { @@ -62,7 +84,10 @@ bool WebCursor::Serialize(Pickle* pickle) const { const char* data = NULL; if (!custom_data_.empty()) data = &custom_data_[0]; - return pickle->WriteData(data, custom_data_.size()); + if (!pickle->WriteData(data, custom_data_.size())) + return false; + + return SerializePlatformData(pickle); } bool WebCursor::IsCustom() const { @@ -70,19 +95,43 @@ bool WebCursor::IsCustom() const { } bool WebCursor::IsEqual(const WebCursor& other) const { - if (!IsCustom()) - return type_ == other.type_; + if (type_ != other.type_) + return false; + + if (!IsPlatformDataEqual(other)) + return false; return hotspot_ == other.hotspot_ && custom_size_ == other.custom_size_ && custom_data_ == other.custom_data_; } +void WebCursor::Clear() { + type_ = WebCore::PlatformCursor::typePointer; + hotspot_.set_x(0); + hotspot_.set_y(0); + custom_size_.set_width(0); + custom_size_.set_height(0); + custom_data_.clear(); + CleanupPlatformData(); +} + +void WebCursor::Copy(const WebCursor& other) { + type_ = other.type_; + hotspot_ = other.hotspot_; + custom_size_ = other.custom_size_; + custom_data_ = other.custom_data_; + CopyPlatformData(other); +} + #if !defined(OS_MACOSX) // The Mac version of Chromium is built with PLATFORM(CG) while all other // versions are PLATFORM(SKIA). We'll keep this Skia implementation here for // common use and put the Mac implementation in webcursor_mac.mm. void WebCursor::SetCustomData(WebCore::Image* image) { + if (!image) + return; + WebCore::NativeImagePtr image_ptr = image->nativeImageForCurrentFrame(); if (!image_ptr) return; diff --git a/webkit/glue/webcursor.h b/webkit/glue/webcursor.h index a64df6c..1dbf3c3 100644 --- a/webkit/glue/webcursor.h +++ b/webkit/glue/webcursor.h @@ -5,6 +5,7 @@ #ifndef WEBKIT_GLUE_WEBCURSOR_H_ #define WEBKIT_GLUE_WEBCURSOR_H_ +#include "base/basictypes.h" #include "base/gfx/point.h" #include "base/gfx/size.h" @@ -40,6 +41,11 @@ class WebCursor { public: WebCursor(); explicit WebCursor(const WebCore::PlatformCursor& platform_cursor); + ~WebCursor(); + + // Copy constructor/assignment operator combine. + WebCursor(const WebCursor& other); + const WebCursor& operator=(const WebCursor& other); // Serialization / De-serialization bool Deserialize(const Pickle* pickle, void** iter); @@ -55,18 +61,16 @@ class WebCursor { bool IsEqual(const WebCursor& other) const; #if defined(OS_WIN) - // If the underlying cursor type is not a custom cursor, this functions uses - // the LoadCursor API to load the cursor and returns it. The caller SHOULD - // NOT pass the resulting handling to DestroyCursor. Returns NULL on error. - HCURSOR GetCursor(HINSTANCE module_handle) const; - - // If the underlying cursor type is a custom cursor, this function generates - // a cursor and returns it. The responsiblity of freeing the cursor handle - // lies with the caller. Returns NULL on error. - HCURSOR GetCustomCursor() const; - - // Initialize this from the given Windows cursor. - void InitFromCursor(HCURSOR handle); + // Returns a HCURSOR representing the current WebCursor instance. + // The ownership of the HCURSOR (does not apply to external cursors) remains + // with the WebCursor instance. + HCURSOR GetCursor(HINSTANCE module_handle); + + // Initialize this from the given Windows cursor. The caller must ensure that + // the HCURSOR remains valid by not invoking the DestroyCursor/DestroyIcon + // APIs on it. + void InitFromExternalCursor(HCURSOR handle); + #elif defined(OS_LINUX) // Return the stock GdkCursorType for this cursor, or GDK_CURSOR_IS_PIXMAP // if it's a custom cursor. @@ -80,6 +84,29 @@ class WebCursor { #endif private: + // Copies the contents of the WebCursor instance passed in. + void Copy(const WebCursor& other); + + // Cleans up the WebCursor instance. + void Clear(); + + // Platform specific initialization goes here. + void InitPlatformData(); + + // Platform specific Serialization / De-serialization + bool SerializePlatformData(Pickle* pickle) const; + bool DeserializePlatformData(const Pickle* pickle, void** iter); + + // Returns true if the platform data in the current cursor object + // matches that of the cursor passed in. + bool IsPlatformDataEqual(const WebCursor& other) const ; + + // Copies platform specific data from the WebCursor instance passed in. + void CopyPlatformData(const WebCursor& other); + + // Platform specific cleanup. + void CleanupPlatformData(); + void SetCustomData(WebCore::Image* image); // WebCore::PlatformCursor type. @@ -91,6 +118,14 @@ class WebCursor { // Platform-inspecific because it can be serialized. gfx::Size custom_size_; std::vector<char> custom_data_; + +#if defined(OS_WIN) + // An externally generated HCURSOR. We assume that it remains valid, i.e we + // don't attempt to copy the HCURSOR. + HCURSOR external_cursor_; + // A custom cursor created from custom bitmap data by Webkit. + HCURSOR custom_cursor_; +#endif // OS_WIN }; #endif // WEBKIT_GLUE_WEBCURSOR_H_ diff --git a/webkit/glue/webcursor_gtk.cc b/webkit/glue/webcursor_gtk.cc index bb66be7..ab8fdfc 100644 --- a/webkit/glue/webcursor_gtk.cc +++ b/webkit/glue/webcursor_gtk.cc @@ -169,3 +169,27 @@ GdkCursor* WebCursor::GetCustomCursor() const { return cursor; } + +void WebCursor::InitPlatformData() { + return; +} + +bool WebCursor::SerializePlatformData(Pickle* pickle) const { + return true; +} + +bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) { + return true; +} + +bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const { + return true; +} + +void WebCursor::CleanupPlatformData() { + return; +} + +void WebCursor::CopyPlatformData(const WebCursor& other) { + return; +} diff --git a/webkit/glue/webcursor_mac.mm b/webkit/glue/webcursor_mac.mm index 12eb0c4..9d83775 100644 --- a/webkit/glue/webcursor_mac.mm +++ b/webkit/glue/webcursor_mac.mm @@ -170,3 +170,26 @@ void WebCursor::SetCustomData(WebCore::Image* image) { CGContextDrawImage(context.get(), rect, image_ptr); } +void WebCursor::InitPlatformData() { + return; +} + +bool WebCursor::SerializePlatformData(Pickle* pickle) const { + return true; +} + +bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) { + return true; +} + +bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const { + return true; +} + +void WebCursor::CleanupPlatformData() { + return; +} + +void WebCursor::CopyPlatformData(const WebCursor& other) { + return; +} diff --git a/webkit/glue/webcursor_win.cc b/webkit/glue/webcursor_win.cc index f4d05d8..b529e06 100644 --- a/webkit/glue/webcursor_win.cc +++ b/webkit/glue/webcursor_win.cc @@ -9,6 +9,7 @@ #undef LOG #include "base/gfx/gdi_util.h" #include "base/logging.h" +#include "base/pickle.h" #include "skia/include/SkBitmap.h" #include "webkit/glue/webcursor.h" #include "webkit/glue/webkit_resources.h" @@ -131,24 +132,27 @@ static PlatformCursor::Type ToPlatformCursorType(HCURSOR cursor) { if (cursor == kStandardCursors[i].cursor) return kStandardCursors[i].type; } - return PlatformCursor::typePointer; + return PlatformCursor::typeCustom; } -HCURSOR WebCursor::GetCursor(HINSTANCE module_handle) const { - if (IsCustom()) - return NULL; +HCURSOR WebCursor::GetCursor(HINSTANCE module_handle){ + if (!IsCustom()) { + const wchar_t* cursor_id = + ToCursorID(static_cast<PlatformCursor::Type>(type_)); - LPCWSTR cursor_id = ToCursorID(static_cast<PlatformCursor::Type>(type_)); + if (IsSystemCursorID(cursor_id)) + module_handle = NULL; - if (IsSystemCursorID(cursor_id)) - module_handle = NULL; + return LoadCursor(module_handle, cursor_id); + } - return LoadCursor(module_handle, cursor_id); -} + if (custom_cursor_) { + DCHECK(external_cursor_ == NULL); + return custom_cursor_; + } -HCURSOR WebCursor::GetCustomCursor() const { - if (!IsCustom()) - return NULL; + if (external_cursor_) + return external_cursor_; BITMAPINFO cursor_bitmap_info = {0}; gfx::CreateBitmapHeader( @@ -176,16 +180,61 @@ HCURSOR WebCursor::GetCustomCursor() const { ii.hbmMask = mask; ii.hbmColor = bitmap_handle; - HCURSOR cursor_handle = CreateIconIndirect(&ii); + custom_cursor_ = CreateIconIndirect(&ii); DeleteObject(mask); DeleteObject(bitmap_handle); DeleteDC(workingDC); ReleaseDC(0, dc); - return cursor_handle; + return custom_cursor_; +} + +void WebCursor::InitFromExternalCursor(HCURSOR cursor) { + WebCore::PlatformCursor::Type cursor_type = ToPlatformCursorType(cursor); + + *this = WebCursor(cursor_type); + + if (cursor_type == WebCore::PlatformCursor::typeCustom) { + external_cursor_ = cursor; + } } -void WebCursor::InitFromCursor(HCURSOR cursor) { - // TODO(iyengar) Add support for custom cursors. - *this = WebCursor(ToPlatformCursorType(cursor)); +void WebCursor::InitPlatformData() { + external_cursor_ = NULL; + custom_cursor_ = NULL; +} + +bool WebCursor::SerializePlatformData(Pickle* pickle) const { + // There are some issues with converting certain HCURSORS to bitmaps. The + // HCURSOR being a user object can be marshaled as is. + return pickle->WriteIntPtr(reinterpret_cast<intptr_t>(external_cursor_)); +} + +bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) { + return pickle->ReadIntPtr(iter, + reinterpret_cast<intptr_t*>(&external_cursor_)); +} + +bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const { + if (!IsCustom()) + return true; + + return (external_cursor_ == other.external_cursor_); +} + +void WebCursor::CopyPlatformData(const WebCursor& other) { + external_cursor_ = other.external_cursor_; + // The custom_cursor_ member will be initialized to a HCURSOR the next time + // the GetCursor member function is invoked on this WebCursor instance. The + // cursor is created using the data in the custom_data_ vector. + custom_cursor_ = NULL; +} + +void WebCursor::CleanupPlatformData() { + external_cursor_ = NULL; + + if (custom_cursor_) { + DestroyIcon(custom_cursor_); + custom_cursor_ = NULL; + } } diff --git a/webkit/glue/webplugin_impl.cc b/webkit/glue/webplugin_impl.cc index 15685e4..003ece7 100644 --- a/webkit/glue/webplugin_impl.cc +++ b/webkit/glue/webplugin_impl.cc @@ -895,11 +895,16 @@ void WebPluginImpl::handleMouseEvent(WebCore::MouseEvent* event) { WebCursor cursor; if (!delegate_->HandleEvent(&np_event, &cursor)) event->setDefaultHandled(); + + ChromeClientImpl* chrome_client = + static_cast<ChromeClientImpl*>( + parent_view->frame()->page()->chrome()->client()); + // A windowless plugin can change the cursor in response to the WM_MOUSEMOVE // event. We need to reflect the changed cursor in the frame view as the // mouse is moved in the boundaries of the windowless plugin. - static_cast<ChromeClientImpl*>( - parent_view->frame()->page()->chrome()->client())->SetCursor(cursor); + chrome_client->SetCursorForPlugin(cursor); + #else NOTIMPLEMENTED(); #endif diff --git a/webkit/tools/test_shell/test_webview_delegate.h b/webkit/tools/test_shell/test_webview_delegate.h index 5c05e34..77c7b8e 100644 --- a/webkit/tools/test_shell/test_webview_delegate.h +++ b/webkit/tools/test_shell/test_webview_delegate.h @@ -22,6 +22,7 @@ #include "base/basictypes.h" #include "base/ref_counted.h" +#include "webkit/glue/webcursor.h" #include "webkit/glue/webview_delegate.h" #include "webkit/glue/webwidget_delegate.h" #if defined(OS_WIN) @@ -66,9 +67,7 @@ class TestWebViewDelegate : public base::RefCounted<TestWebViewDelegate>, #else , select_trailing_whitespace_enabled_(false) #endif -#if defined(OS_WIN) - , custom_cursor_(NULL) -#elif defined(OS_LINUX) +#if defined(OS_LINUX) , cursor_type_(GDK_X_CURSOR) #endif { @@ -310,9 +309,8 @@ class TestWebViewDelegate : public base::RefCounted<TestWebViewDelegate>, // true if we want to enable selection of trailing whitespaces bool select_trailing_whitespace_enabled_; + WebCursor current_cursor_; #if defined(OS_WIN) - HCURSOR custom_cursor_; - // Classes needed by drag and drop. scoped_refptr<TestDragDelegate> drag_delegate_; scoped_refptr<TestDropDelegate> drop_delegate_; diff --git a/webkit/tools/test_shell/test_webview_delegate_gtk.cc b/webkit/tools/test_shell/test_webview_delegate_gtk.cc index 6db73b4..831691a 100644 --- a/webkit/tools/test_shell/test_webview_delegate_gtk.cc +++ b/webkit/tools/test_shell/test_webview_delegate_gtk.cc @@ -111,13 +111,14 @@ void TestWebViewDelegate::CloseWidgetSoon(WebWidget* webwidget) { void TestWebViewDelegate::SetCursor(WebWidget* webwidget, const WebCursor& cursor) { - GdkCursorType cursor_type = cursor.GetCursorType(); + current_cursor_ = cursor; + GdkCursorType cursor_type = current_cursor_.GetCursorType(); GdkCursor* gdk_cursor; if (cursor_type == GDK_CURSOR_IS_PIXMAP) { // TODO(port): WebKit bug https://bugs.webkit.org/show_bug.cgi?id=16388 is // that calling gdk_window_set_cursor repeatedly is expensive. We should // avoid it here where possible. - gdk_cursor = cursor.GetCustomCursor(); + gdk_cursor = current_cursor_.GetCustomCursor(); } else { // Optimize the common case, where the cursor hasn't changed. // However, we can switch between different pixmaps, so only on the diff --git a/webkit/tools/test_shell/test_webview_delegate_win.cc b/webkit/tools/test_shell/test_webview_delegate_win.cc index cea089a..30431f6 100644 --- a/webkit/tools/test_shell/test_webview_delegate_win.cc +++ b/webkit/tools/test_shell/test_webview_delegate_win.cc @@ -36,8 +36,6 @@ // WebViewDelegate ----------------------------------------------------------- TestWebViewDelegate::~TestWebViewDelegate() { - if (custom_cursor_) - DestroyIcon(custom_cursor_); RevokeDragDrop(shell_->webViewWnd()); } @@ -89,17 +87,9 @@ void TestWebViewDelegate::CloseWidgetSoon(WebWidget* webwidget) { void TestWebViewDelegate::SetCursor(WebWidget* webwidget, const WebCursor& cursor) { if (WebWidgetHost* host = GetHostForWidget(webwidget)) { - if (custom_cursor_) { - DestroyIcon(custom_cursor_); - custom_cursor_ = NULL; - } - if (cursor.IsCustom()) { - custom_cursor_ = cursor.GetCustomCursor(); - host->SetCursor(custom_cursor_); - } else { - HINSTANCE mod_handle = GetModuleHandle(NULL); - host->SetCursor(cursor.GetCursor(mod_handle)); - } + current_cursor_ = cursor; + HINSTANCE mod_handle = GetModuleHandle(NULL); + host->SetCursor(current_cursor_.GetCursor(mod_handle)); } } |