diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-15 20:12:50 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-15 20:12:50 +0000 |
commit | dc714a8fc38ee88f330094cff5c76106542b00fa (patch) | |
tree | b96c6d385be033bf945e8004f6f6c98fbda0bd61 | |
parent | d4de666a8ad7f5ba0321e11f317ed89f9dd16dd5 (diff) | |
download | chromium_src-dc714a8fc38ee88f330094cff5c76106542b00fa.zip chromium_src-dc714a8fc38ee88f330094cff5c76106542b00fa.tar.gz chromium_src-dc714a8fc38ee88f330094cff5c76106542b00fa.tar.bz2 |
Fix hang when a plugin has child windows that are in a different process. RedrawWindow would synchronously wait for the child window, during which only some messages are pumped. This leads to reentrancy with our custom paint message. Avoiding synchronously calling the child windows in the reentrancy fixes the problem.
BUG=2242480
Review URL: http://codereview.chromium.org/501014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34593 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_win.cc | 99 |
1 files changed, 56 insertions, 43 deletions
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_win.cc b/webkit/glue/plugins/webplugin_delegate_impl_win.cc index f43e165..e3ee2f8 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_win.cc +++ b/webkit/glue/plugins/webplugin_delegate_impl_win.cc @@ -815,28 +815,6 @@ LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc( return TRUE; } - static UINT custom_msg = RegisterWindowMessage(kPaintMessageName); - if (message == custom_msg) { - // Get the invalid rect which is in screen coordinates and convert to - // window coordinates. - gfx::Rect invalid_rect; - invalid_rect.set_x(wparam >> 16); - invalid_rect.set_y(wparam & 0xFFFF); - invalid_rect.set_width(lparam >> 16); - invalid_rect.set_height(lparam & 0xFFFF); - - RECT window_rect; - GetWindowRect(hwnd, &window_rect); - invalid_rect.Offset(-window_rect.left, -window_rect.top); - - // The plugin window might have non-client area. If we don't pass in - // RDW_FRAME then the children don't receive WM_NCPAINT messages while - // scrolling, which causes painting problems (http://b/issue?id=923945). - RedrawWindow(hwnd, &invalid_rect.ToRECT(), NULL, - RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME); - return FALSE; - } - // Maintain a local/global stack for the g_current_plugin_instance variable // as this may be a nested invocation. WebPluginDelegateImpl* last_plugin_instance = g_current_plugin_instance; @@ -854,35 +832,70 @@ LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc( return FALSE; } + LRESULT result; + uint32 old_message = delegate->last_message_; delegate->last_message_ = message; - delegate->is_calling_wndproc = true; - if (!delegate->user_gesture_message_posted_ && - IsUserGestureMessage(message)) { - delegate->user_gesture_message_posted_ = true; + static UINT custom_msg = RegisterWindowMessage(kPaintMessageName); + if (message == custom_msg) { + // Get the invalid rect which is in screen coordinates and convert to + // window coordinates. + gfx::Rect invalid_rect; + invalid_rect.set_x(wparam >> 16); + invalid_rect.set_y(wparam & 0xFFFF); + invalid_rect.set_width(lparam >> 16); + invalid_rect.set_height(lparam & 0xFFFF); - delegate->instance()->PushPopupsEnabledState(true); + RECT window_rect; + GetWindowRect(hwnd, &window_rect); + invalid_rect.Offset(-window_rect.left, -window_rect.top); - MessageLoop::current()->PostDelayedTask(FROM_HERE, - delegate->user_gesture_msg_factory_.NewRunnableMethod( - &WebPluginDelegateImpl::OnUserGestureEnd), - kWindowedPluginPopupTimerMs); - } + // The plugin window might have non-client area. If we don't pass in + // RDW_FRAME then the children don't receive WM_NCPAINT messages while + // scrolling, which causes painting problems (http://b/issue?id=923945). + uint32 flags = RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME; + + // If a plugin (like Google Earth or Java) has child windows that are hosted + // in a different process, then RedrawWindow with UPDATENOW will + // synchronously wait for this call to complete. Some messages are pumped + // but not others, which could lead to a deadlock. So avoid reentrancy by + // only synchronously calling RedrawWindow once at a time. + if (old_message != custom_msg) + flags |= RDW_UPDATENOW; + + RedrawWindow(hwnd, &invalid_rect.ToRECT(), NULL, flags); + result = FALSE; + } else { + delegate->is_calling_wndproc = true; - LRESULT result = CallWindowProc(delegate->plugin_wnd_proc_, hwnd, message, - wparam, lparam); - delegate->is_calling_wndproc = false; - g_current_plugin_instance = last_plugin_instance; + if (!delegate->user_gesture_message_posted_ && + IsUserGestureMessage(message)) { + delegate->user_gesture_message_posted_ = true; + + delegate->instance()->PushPopupsEnabledState(true); - if (message == WM_NCDESTROY) { - RemoveProp(hwnd, kWebPluginDelegateProperty); - ATOM plugin_name_atom = reinterpret_cast<ATOM>( - RemoveProp(hwnd, kPluginNameAtomProperty)); - if (plugin_name_atom != 0) - GlobalDeleteAtom(plugin_name_atom); - ClearThrottleQueueForWindow(hwnd); + MessageLoop::current()->PostDelayedTask(FROM_HERE, + delegate->user_gesture_msg_factory_.NewRunnableMethod( + &WebPluginDelegateImpl::OnUserGestureEnd), + kWindowedPluginPopupTimerMs); + } + + result = CallWindowProc( + delegate->plugin_wnd_proc_, hwnd, message, wparam, lparam); + delegate->is_calling_wndproc = false; + g_current_plugin_instance = last_plugin_instance; + + if (message == WM_NCDESTROY) { + RemoveProp(hwnd, kWebPluginDelegateProperty); + ATOM plugin_name_atom = reinterpret_cast<ATOM>( + RemoveProp(hwnd, kPluginNameAtomProperty)); + if (plugin_name_atom != 0) + GlobalDeleteAtom(plugin_name_atom); + ClearThrottleQueueForWindow(hwnd); + } } + delegate->last_message_ = old_message; return result; } |