diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-14 01:06:08 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-14 01:06:08 +0000 |
commit | 7bdd2b9e9114998905a00f256790ebf003064f8a (patch) | |
tree | 62da14b708473b37acc2fe9836b7618a2065f2e3 | |
parent | 01c553f08001332cb00cdb7bb7f02256a0146fe0 (diff) | |
download | chromium_src-7bdd2b9e9114998905a00f256790ebf003064f8a.zip chromium_src-7bdd2b9e9114998905a00f256790ebf003064f8a.tar.gz chromium_src-7bdd2b9e9114998905a00f256790ebf003064f8a.tar.bz2 |
Make WidgetWin redraw child windows that are in a different process asynchronously.
This helps with jank (i.e. bug 11701 which I couldn't repro with this) and also with deadlocks (fixes 11421 for painting).
BUG=11421,11701
Review URL: http://codereview.chromium.org/115216
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16027 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/test/ui/npapi_uitest.cc | 22 | ||||
-rw-r--r-- | views/widget/widget_win.cc | 33 | ||||
-rw-r--r-- | webkit/glue/plugins/test/plugin_client.cc | 12 | ||||
-rw-r--r-- | webkit/glue/plugins/test/plugin_windowed_test.cc | 84 | ||||
-rw-r--r-- | webkit/glue/plugins/test/plugin_windowed_test.h | 9 |
5 files changed, 147 insertions, 13 deletions
diff --git a/chrome/test/ui/npapi_uitest.cc b/chrome/test/ui/npapi_uitest.cc index d720af9..d1ad73e 100644 --- a/chrome/test/ui/npapi_uitest.cc +++ b/chrome/test/ui/npapi_uitest.cc @@ -192,6 +192,28 @@ TEST_F(NPAPIVisiblePluginTester, CreateInstanceInPaint) { kTestCompleteSuccess, kShortWaitTimeout); } +#if defined(OS_WIN) + +// Tests that putting up an alert in response to a paint doesn't deadlock. +TEST_F(NPAPIVisiblePluginTester, AlertInWindowMessage) { + show_window_ = true; + std::wstring test_case = L"alert_in_window_message.html"; + GURL url = GetTestUrl(L"npapi", test_case); + NavigateToURL(url); + + bool modal_dialog_showing = false; + MessageBoxFlags::DialogButton available_buttons; + ASSERT_TRUE(automation()->WaitForAppModalDialog(kShortWaitTimeout)); + ASSERT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, + &available_buttons)); + ASSERT_TRUE(modal_dialog_showing); + ASSERT_TRUE((MessageBoxFlags::DIALOGBUTTON_OK & available_buttons) != 0); + ASSERT_TRUE(automation()->ClickAppModalDialogButton( + MessageBoxFlags::DIALOGBUTTON_OK)); +} + +#endif + TEST_F(NPAPIVisiblePluginTester, VerifyNPObjectLifetimeTest) { if (!UITest::in_process_renderer()) { show_window_ = true; diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc index 4a4e27e..759bcc9 100644 --- a/views/widget/widget_win.cc +++ b/views/widget/widget_win.cc @@ -259,6 +259,22 @@ gfx::NativeView WidgetWin::GetNativeView() const { return hwnd_; } +static BOOL CALLBACK EnumChildProcForRedraw(HWND hwnd, LPARAM lparam) { + DWORD process_id; + GetWindowThreadProcessId(hwnd, &process_id); + gfx::Rect invalid_rect = *reinterpret_cast<gfx::Rect*>(lparam); + + RECT window_rect; + GetWindowRect(hwnd, &window_rect); + invalid_rect.Offset(-window_rect.left, -window_rect.top); + + int flags = RDW_INVALIDATE | RDW_NOCHILDREN; + if (process_id == GetCurrentProcessId()) + flags |= RDW_UPDATENOW; + RedrawWindow(hwnd, &invalid_rect.ToRECT(), NULL, flags); + return TRUE; +} + void WidgetWin::PaintNow(const gfx::Rect& update_rect) { if (use_layered_buffer_) { PaintLayeredWindow(); @@ -273,9 +289,20 @@ void WidgetWin::PaintNow(const gfx::Rect& update_rect) { ::RedrawWindow(GetParent(), parent_update_rect, NULL, RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN); } else { - RECT native_update_rect = update_rect.ToRECT(); - RedrawWindow(hwnd_, &native_update_rect, NULL, - RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN); + // Paint child windows that are in a different process asynchronously. + // This prevents a hang in other processes from blocking this process. + ::RedrawWindow(hwnd_, &update_rect.ToRECT(), NULL, + RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN); + + // Send the invalid rect in screen coordinates. + CRect screen_rect_temp; + GetWindowRect(&screen_rect_temp); + gfx::Rect screen_rect(screen_rect_temp); + gfx::Rect invalid_screen_rect = update_rect; + invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y()); + + LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect); + EnumChildWindows(hwnd_, EnumChildProcForRedraw, lparam); } // As we were created with a style of WS_CLIPCHILDREN redraw requests may // result in an empty paint rect in WM_PAINT (this'll happen if a diff --git a/webkit/glue/plugins/test/plugin_client.cc b/webkit/glue/plugins/test/plugin_client.cc index 7a92de4..fe0a4c6 100644 --- a/webkit/glue/plugins/test/plugin_client.cc +++ b/webkit/glue/plugins/test/plugin_client.cc @@ -5,9 +5,6 @@ #include "base/string_util.h" #include "webkit/glue/plugins/test/plugin_client.h" #include "webkit/glue/plugins/test/plugin_arguments_test.h" -#if defined(OS_WIN) -#include "webkit/glue/plugins/test/plugin_create_instance_in_paint.h" -#endif #include "webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h" #include "webkit/glue/plugins/test/plugin_get_javascript_url_test.h" #include "webkit/glue/plugins/test/plugin_geturl_test.h" @@ -17,7 +14,9 @@ #include "webkit/glue/plugins/test/plugin_npobject_lifetime_test.h" #include "webkit/glue/plugins/test/plugin_npobject_proxy_test.h" #include "webkit/glue/plugins/test/plugin_window_size_test.h" +#if defined(OS_WIN) #include "webkit/glue/plugins/test/plugin_windowed_test.h" +#endif #include "webkit/glue/plugins/test/plugin_windowless_test.h" #include "third_party/npapi/bindings/npapi.h" #include "third_party/npapi/bindings/npruntime.h" @@ -123,9 +122,6 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, } else if (test_name == "checkwindowrect") { new_test = new NPAPIClient::PluginWindowSizeTest(instance, NPAPIClient::PluginClient::HostFunctions()); - } else if (test_name == "create_instance_in_paint") { - new_test = new NPAPIClient::CreateInstanceInPaintTest(instance, - NPAPIClient::PluginClient::HostFunctions()); #endif } else if (test_name == "self_delete_plugin_stream") { new_test = new NPAPIClient::DeletePluginInStreamTest(instance, @@ -156,7 +152,9 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, NPAPIClient::PluginClient::HostFunctions()); #if defined(OS_WIN) // TODO(port): plugin_windowed_test.*. - } else if (test_name == "hidden_plugin") { + } else if (test_name == "hidden_plugin" || + test_name == "create_instance_in_paint" || + test_name == "alert_in_window_message") { new_test = new NPAPIClient::WindowedPluginTest(instance, NPAPIClient::PluginClient::HostFunctions()); #endif diff --git a/webkit/glue/plugins/test/plugin_windowed_test.cc b/webkit/glue/plugins/test/plugin_windowed_test.cc index 4001ba2..79e662b 100644 --- a/webkit/glue/plugins/test/plugin_windowed_test.cc +++ b/webkit/glue/plugins/test/plugin_windowed_test.cc @@ -8,17 +8,95 @@ namespace NPAPIClient { WindowedPluginTest::WindowedPluginTest(NPP id, NPNetscapeFuncs *host_functions) - : PluginTest(id, host_functions) { + : PluginTest(id, host_functions), + window_(NULL), done_(false) { +} + +WindowedPluginTest::~WindowedPluginTest() { + if (window_) + DestroyWindow(window_); } NPError WindowedPluginTest::SetWindow(NPWindow* pNPWindow) { - HWND window = reinterpret_cast<HWND>(pNPWindow->window); - if (!pNPWindow || !::IsWindow(window)) { + if (test_name() == "create_instance_in_paint" && test_id() == "2") { + SignalTestCompleted(); + return NPERR_NO_ERROR; + } + + if (window_) + return NPERR_NO_ERROR; + + HWND parent = reinterpret_cast<HWND>(pNPWindow->window); + if (!pNPWindow || !::IsWindow(parent)) { SetError("Invalid arguments passed in"); return NPERR_INVALID_PARAM; } + if ((test_name() == "create_instance_in_paint" && test_id() == "1") || + test_name() == "alert_in_window_message") { + static ATOM window_class = 0; + if (!window_class) { + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_DBLCLKS; + wcex.lpfnWndProc = &NPAPIClient::WindowedPluginTest::WindowProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hIcon = 0; + wcex.hCursor = 0; + wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1); + wcex.lpszMenuName = 0; + wcex.lpszClassName = L"CreateInstanceInPaintTestWindowClass"; + wcex.hIconSm = 0; + window_class = RegisterClassEx(&wcex); + } + + window_ = CreateWindowEx( + WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, + MAKEINTATOM(window_class), 0, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE , + 0, 0, 100, 100, parent, 0, GetModuleHandle(NULL), 0); + DCHECK(window_); + ::SetProp(window_, L"Plugin_Instance", this); + } + return NPERR_NO_ERROR; } +void WindowedPluginTest::CallJSFunction( + WindowedPluginTest* this_ptr, const char* function) { + NPIdentifier function_id = this_ptr->HostFunctions()->getstringidentifier( + function); + + NPObject *window_obj = NULL; + this_ptr->HostFunctions()->getvalue( + this_ptr->id(), NPNVWindowNPObject, &window_obj); + + NPVariant rv; + this_ptr->HostFunctions()->invoke( + this_ptr->id(), window_obj, function_id, NULL, 0, &rv); +} + +LRESULT CALLBACK WindowedPluginTest::WindowProc( + HWND window, UINT message, WPARAM wparam, LPARAM lparam) { + WindowedPluginTest* this_ptr = + reinterpret_cast<WindowedPluginTest*> + (::GetProp(window, L"Plugin_Instance")); + + if (this_ptr && !this_ptr->done_) { + if (this_ptr->test_name() == "create_instance_in_paint" && + message == WM_PAINT) { + this_ptr->done_ = true; + CallJSFunction(this_ptr, "CreateNewInstance"); + } else if (this_ptr->test_name() == "alert_in_window_message" && + message == WM_PAINT) { + this_ptr->done_ = true; + CallJSFunction(this_ptr, "CallAlert"); + } + } + + return DefWindowProc(window, message, wparam, lparam); +} + } // namespace NPAPIClient diff --git a/webkit/glue/plugins/test/plugin_windowed_test.h b/webkit/glue/plugins/test/plugin_windowed_test.h index 547b079..cd0b875 100644 --- a/webkit/glue/plugins/test/plugin_windowed_test.h +++ b/webkit/glue/plugins/test/plugin_windowed_test.h @@ -14,7 +14,16 @@ namespace NPAPIClient { class WindowedPluginTest : public PluginTest { public: WindowedPluginTest(NPP id, NPNetscapeFuncs *host_functions); + ~WindowedPluginTest(); virtual NPError SetWindow(NPWindow* pNPWindow); + + private: + static LRESULT CALLBACK WindowProc( + HWND window, UINT message, WPARAM wparam, LPARAM lparam); + static void CallJSFunction(WindowedPluginTest*, const char*); + + HWND window_; + bool done_; }; } // namespace NPAPIClient |