summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/plugin_process_host.cc97
-rw-r--r--chrome/browser/plugin_process_host.h3
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.cc98
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.h3
-rw-r--r--chrome/common/plugin_messages_internal.h7
-rw-r--r--chrome/plugin/webplugin_proxy.cc39
-rw-r--r--chrome/plugin/webplugin_proxy.h4
-rw-r--r--chrome/test/data/npapi/create_instance_in_paint.html44
-rw-r--r--chrome/test/ui/npapi_test_helper.cc27
-rw-r--r--chrome/test/ui/npapi_test_helper.h36
-rw-r--r--chrome/test/ui/npapi_uitest.cc46
11 files changed, 188 insertions, 216 deletions
diff --git a/chrome/browser/plugin_process_host.cc b/chrome/browser/plugin_process_host.cc
index 6cea0c7..9ed3dbf 100644
--- a/chrome/browser/plugin_process_host.cc
+++ b/chrome/browser/plugin_process_host.cc
@@ -254,92 +254,16 @@ void PluginDownloadUrlHelper::DownloadCompletedHelper(bool success) {
delete this;
}
-
-// Sends the reply to the create window message on the IO thread.
-class SendReplyTask : public Task {
- public:
- SendReplyTask(FilePath plugin_path, HWND window, IPC::Message* reply_msg)
- : plugin_path_(plugin_path),
- reply_msg_(reply_msg),
- window_(window){ }
-
- virtual void Run() {
- PluginProcessHost* plugin =
- PluginService::GetInstance()->FindPluginProcess(plugin_path_);
- if (!plugin)
- return;
-
- plugin->AddWindow(window_);
- plugin->Send(reply_msg_);
- }
-
- private:
- FilePath plugin_path_;
- IPC::Message* reply_msg_;
- HWND window_;
-};
-
-// Creates a child window of the given HWND on the UI thread.
-class CreateWindowTask : public Task {
- public:
- CreateWindowTask(
- FilePath plugin_path, HWND parent, IPC::Message* reply_msg)
- : plugin_path_(plugin_path), parent_(parent), reply_msg_(reply_msg) { }
-
- virtual void Run() {
- static ATOM window_class = 0;
- if (!window_class) {
- WNDCLASSEX wcex;
- wcex.cbSize = sizeof(WNDCLASSEX);
- wcex.style = CS_DBLCLKS;
- wcex.lpfnWndProc = DefWindowProc;
- 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 = kWrapperNativeWindowClassName;
- wcex.hIconSm = 0;
- window_class = RegisterClassEx(&wcex);
- }
-
- HWND window = CreateWindowEx(
- WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
- MAKEINTATOM(window_class), 0,
- WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
- 0, 0, 0, 0, parent_, 0, GetModuleHandle(NULL), 0);
- TRACK_HWND_CREATION(window);
-
- PluginProcessHostMsg_CreateWindow::WriteReplyParams(
- reply_msg_, window);
-
- g_browser_process->io_thread()->message_loop()->PostTask(
- FROM_HERE, new SendReplyTask(plugin_path_, window, reply_msg_));
- }
-
- private:
- FilePath plugin_path_;
- HWND parent_;
- IPC::Message* reply_msg_;
-};
-
-void PluginProcessHost::OnCreateWindow(HWND parent,
- IPC::Message* reply_msg) {
- // Need to create this window on the UI thread.
- PluginService::GetInstance()->main_message_loop()->PostTask(
- FROM_HERE, new CreateWindowTask(info_.path, parent, reply_msg));
-}
-
-void PluginProcessHost::OnDestroyWindow(HWND window) {
+void PluginProcessHost::OnPluginWindowDestroyed(HWND window, HWND parent) {
+ // The window is destroyed at this point, we just care about its parent, which
+ // is the intermediate window we created.
std::set<HWND>::iterator window_index =
- plugin_parent_windows_set_.find(window);
- if (window_index != plugin_parent_windows_set_.end()) {
- plugin_parent_windows_set_.erase(window_index);
- }
+ plugin_parent_windows_set_.find(parent);
+ if (window_index == plugin_parent_windows_set_.end())
+ return;
- PostMessage(window, WM_CLOSE, 0, 0);
+ plugin_parent_windows_set_.erase(window_index);
+ PostMessage(parent, WM_CLOSE, 0, 0);
}
void PluginProcessHost::OnDownloadUrl(const std::string& url,
@@ -499,9 +423,8 @@ void PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginProcessHostMsg_ResolveProxy,
OnResolveProxy)
#if defined(OS_WIN)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginProcessHostMsg_CreateWindow,
- OnCreateWindow)
- IPC_MESSAGE_HANDLER(PluginProcessHostMsg_DestroyWindow, OnDestroyWindow)
+ IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginWindowDestroyed,
+ OnPluginWindowDestroyed)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_DownloadUrl, OnDownloadUrl)
#endif
IPC_MESSAGE_UNHANDLED_ERROR()
diff --git a/chrome/browser/plugin_process_host.h b/chrome/browser/plugin_process_host.h
index c43fef2..a326bee 100644
--- a/chrome/browser/plugin_process_host.h
+++ b/chrome/browser/plugin_process_host.h
@@ -104,8 +104,7 @@ class PluginProcessHost : public ChildProcessHost,
void OnPluginMessage(const std::vector<uint8>& data);
#if defined(OS_WIN)
- void OnCreateWindow(HWND parent, IPC::Message* reply_msg);
- void OnDestroyWindow(HWND window);
+ void OnPluginWindowDestroyed(HWND window, HWND parent);
void OnDownloadUrl(const std::string& url, int source_pid,
gfx::NativeWindow caller_window);
#endif
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc
index fb243d3..1a29a99 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc
@@ -11,7 +11,9 @@
#include "base/win_util.h"
#include "chrome/browser/browser_accessibility.h"
#include "chrome/browser/browser_accessibility_manager.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_trial.h"
+#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
@@ -116,6 +118,33 @@ static bool GetNewTextDirection(WebTextDirection* direction) {
return true;
}
+class NotifyPluginProcessHostTask : public Task {
+ public:
+ NotifyPluginProcessHostTask(HWND window, HWND parent)
+ : window_(window), parent_(parent) { }
+
+ private:
+ void Run() {
+ DWORD plugin_process_id;
+ GetWindowThreadProcessId(window_, &plugin_process_id);
+ for (ChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
+ !iter.Done(); ++iter) {
+ PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
+ if (plugin->GetProcessId() == plugin_process_id) {
+ plugin->AddWindow(parent_);
+ return;
+ }
+ }
+
+ // The plugin process might have died in the time to execute the task, don't
+ // leak the HWND.
+ PostMessage(parent_, WM_CLOSE, 0, 0);
+ }
+
+ HWND window_; // Plugin HWND, created and destroyed in the plugin process.
+ HWND parent_; // Parent HWND, created and destroyed on the browser UI thread.
+};
+
} // namespace
// RenderWidgetHostView --------------------------------------------------------
@@ -219,6 +248,10 @@ void RenderWidgetHostViewWin::MovePluginWindows(
if (plugin_window_moves.empty())
return;
+ bool oop_plugins =
+ !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessPlugins);
+
HDWP defer_window_pos_info =
::BeginDeferWindowPos(static_cast<int>(plugin_window_moves.size()));
@@ -230,18 +263,36 @@ void RenderWidgetHostViewWin::MovePluginWindows(
for (size_t i = 0; i < plugin_window_moves.size(); ++i) {
unsigned long flags = 0;
const WebPluginGeometry& move = plugin_window_moves[i];
+ HWND window = move.window;
// As the plugin parent window which lives on the browser UI thread is
// destroyed asynchronously, it is possible that we have a stale window
// sent in by the renderer for moving around.
- if (!::IsWindow(move.window))
+ // Note: get the parent before checking if the window is valid, to avoid a
+ // race condition where the window is destroyed after the check but before
+ // the GetParent call.
+ HWND parent = ::GetParent(window);
+ if (!::IsWindow(window))
continue;
- // The renderer should only be trying to move windows that are children
- // of its render widget window.
- if (::IsChild(m_hWnd, move.window) == 0) {
- NOTREACHED();
- continue;
+ if (oop_plugins) {
+ if (parent == m_hWnd) {
+ // The plugin window is a direct child of this window, add an
+ // intermediate window that lives on this thread to speed up scrolling.
+ // Note this only works with out of process plugins since we depend on
+ // PluginProcessHost to destroy the intermediate HWNDs.
+ parent = ReparentWindow(window);
+ ::ShowWindow(window, SW_SHOW); // Window was created hidden.
+ } else if (::GetParent(parent) != m_hWnd) {
+ // The renderer should only be trying to move windows that are children
+ // of its render widget window.
+ NOTREACHED();
+ continue;
+ }
+
+ // We move the intermediate parent window which doesn't result in cross-
+ // process synchronous Windows messages.
+ window = parent;
}
if (move.visible)
@@ -257,10 +308,10 @@ void RenderWidgetHostViewWin::MovePluginWindows(
// Note: System will own the hrgn after we call SetWindowRgn,
// so we don't need to call DeleteObject(hrgn)
- ::SetWindowRgn(move.window, hrgn, !move.clip_rect.IsEmpty());
+ ::SetWindowRgn(window, hrgn, !move.clip_rect.IsEmpty());
defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info,
- move.window, NULL,
+ window, NULL,
move.window_rect.x(),
move.window_rect.y(),
move.window_rect.width(),
@@ -274,6 +325,37 @@ void RenderWidgetHostViewWin::MovePluginWindows(
::EndDeferWindowPos(defer_window_pos_info);
}
+HWND RenderWidgetHostViewWin::ReparentWindow(HWND window) {
+ static ATOM window_class = 0;
+ if (!window_class) {
+ WNDCLASSEX wcex;
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_DBLCLKS;
+ wcex.lpfnWndProc = ::DefWindowProc;
+ 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 = kWrapperNativeWindowClassName;
+ wcex.hIconSm = 0;
+ window_class = RegisterClassEx(&wcex);
+ }
+
+ HWND parent = CreateWindowEx(
+ WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
+ MAKEINTATOM(window_class), 0,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ 0, 0, 0, 0, ::GetParent(window), 0, GetModuleHandle(NULL), 0);
+ DCHECK(parent);
+ ::SetParent(window, parent);
+ g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
+ new NotifyPluginProcessHostTask(window, parent));
+ return parent;
+}
+
void RenderWidgetHostViewWin::Focus() {
if (IsWindow())
SetFocus();
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h
index 893e129..3501ca1 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.h
@@ -210,6 +210,9 @@ class RenderWidgetHostViewWin :
// given paint rect.
void DrawResizeCorner(const gfx::Rect& paint_rect, HDC dc);
+ // Create an intermediate window between the given HWND and its parent.
+ HWND ReparentWindow(HWND window);
+
// The associated Model.
RenderWidgetHost* render_widget_host_;
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index 11a0365..54839fb 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -78,9 +78,10 @@ IPC_BEGIN_MESSAGES(PluginProcessHost)
HWND /* parent */,
HWND /* child */)
- // Destroys the given window on the UI thread.
- IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_DestroyWindow,
- HWND /* window */)
+ // Destroys the given window's parent on the UI thread.
+ IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginWindowDestroyed,
+ HWND /* window */,
+ HWND /* parent */)
IPC_MESSAGE_ROUTED3(PluginProcessHostMsg_DownloadUrl,
std::string /* URL */,
diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc
index 7933082..6a827ce 100644
--- a/chrome/plugin/webplugin_proxy.cc
+++ b/chrome/plugin/webplugin_proxy.cc
@@ -38,49 +38,28 @@ WebPluginProxy::WebPluginProxy(
delegate_(delegate),
waiting_for_paint_(false),
#pragma warning(suppress: 4355) // can use this
- runnable_method_factory_(this),
- parent_window_(NULL) {
+ runnable_method_factory_(this) {
}
WebPluginProxy::~WebPluginProxy() {
if (cp_browsing_context_)
GetContextMap().erase(cp_browsing_context_);
-
- if (parent_window_) {
- PluginThread::current()->Send(
- new PluginProcessHostMsg_DestroyWindow(parent_window_));
- }
}
bool WebPluginProxy::Send(IPC::Message* msg) {
return channel_->Send(msg);
}
-bool WebPluginProxy::SetWindow(gfx::NativeView window) {
- if (window) {
- // To make scrolling windowed plugins fast, we create the page's direct
- // child windows in the browser process. This way no cross process messages
- // are sent.
- HWND old_parent = GetParent(window);
- IPC::SyncMessage* msg = new PluginProcessHostMsg_CreateWindow(
- old_parent, &parent_window_);
-
- // Need to process window messages in the meantime to avoid a deadlock if
- // the browser paints or sends any other (synchronous) WM_ message to the
- // plugin window.
- msg->EnableMessagePumping();
- PluginThread::current()->Send(msg);
-
- SetParent(window, parent_window_);
-
- // We want the browser process to move this window which has a message loop
- // in its process.
- window = parent_window_;
- }
-
+void WebPluginProxy::SetWindow(gfx::NativeView window) {
Send(new PluginHostMsg_SetWindow(route_id_, gfx::IdFromNativeView(window)));
+}
- return false;
+void WebPluginProxy::WillDestroyWindow(gfx::NativeView window) {
+#if defined(OS_WIN)
+ PluginThread::current()->Send(
+ new PluginProcessHostMsg_PluginWindowDestroyed(
+ window, ::GetParent(window)));
+#endif
}
#if defined(OS_WIN)
diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h
index 8c4629d..ea2c124 100644
--- a/chrome/plugin/webplugin_proxy.h
+++ b/chrome/plugin/webplugin_proxy.h
@@ -34,7 +34,8 @@ class WebPluginProxy : public WebPlugin {
~WebPluginProxy();
// WebPlugin overrides
- bool SetWindow(gfx::NativeView window);
+ void SetWindow(gfx::NativeView window);
+ void WillDestroyWindow(gfx::NativeView window);
#if defined(OS_WIN)
void SetWindowlessPumpEvent(HANDLE pump_messages_event);
void SetModalDialogEvent(HANDLE modal_dialog_event);
@@ -136,7 +137,6 @@ class WebPluginProxy : public WebPlugin {
bool waiting_for_paint_;
uint32 cp_browsing_context_;
scoped_ptr<base::WaitableEvent> modal_dialog_event_;
- HWND parent_window_;
// Variables used for desynchronized windowless plugin painting. See note in
// webplugin_delegate_proxy.h for how this works.
diff --git a/chrome/test/data/npapi/create_instance_in_paint.html b/chrome/test/data/npapi/create_instance_in_paint.html
new file mode 100644
index 0000000..80e8935
--- /dev/null
+++ b/chrome/test/data/npapi/create_instance_in_paint.html
@@ -0,0 +1,44 @@
+<html>
+
+<head>
+<script src="npapi.js"></script>
+</head>
+
+<body>
+<div id="statusPanel" style="border: 1px solid red; width: 100%">
+Test running....
+</div>
+
+
+Plugin Instance In Paint Test<p>
+
+Tests that there's no deadlock when a plugin instance is created while handling a paint message.
+
+<DIV ID="PluginDiv">
+<embed type="application/vnd.npapi-test"
+ src="foo"
+ name="create_instance_in_paint"
+ id="1"
+ mode="np_embed"
+>
+</DIV>
+
+<DIV id="PluginDiv2"></DIV>
+
+<script>
+var height = document.body.offsetHeight;
+
+
+function CreateNewInstance() {
+ var obj = document.createElement('embed');
+ obj.setAttribute('type', 'application/vnd.npapi-test');
+ obj.setAttribute('src', 'bar');
+ obj.setAttribute('name', 'create_instance_in_paint');
+ obj.setAttribute('id', '2');
+ obj.setAttribute('mode', 'np_embed');
+ document.getElementById("PluginDiv2").appendChild(obj);
+}
+</script>
+
+</body>
+</html>
diff --git a/chrome/test/ui/npapi_test_helper.cc b/chrome/test/ui/npapi_test_helper.cc
index 859d3df..ab891f6 100644
--- a/chrome/test/ui/npapi_test_helper.cc
+++ b/chrome/test/ui/npapi_test_helper.cc
@@ -4,30 +4,9 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// NPAPI test helper classes.
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#include "chrome/test/ui/npapi_test_helper.h"
diff --git a/chrome/test/ui/npapi_test_helper.h b/chrome/test/ui/npapi_test_helper.h
index 7b79e0e..6af2d73 100644
--- a/chrome/test/ui/npapi_test_helper.h
+++ b/chrome/test/ui/npapi_test_helper.h
@@ -1,31 +1,9 @@
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TEST_HELPER_H_
+#define CHROME_TEST_HELPER_H_
#include "chrome/test/ui/ui_test.h"
@@ -52,3 +30,5 @@ class NPAPIIncognitoTester : public NPAPITester {
protected:
virtual void SetUp();
};
+
+#endif // CHROME_TEST_HELPER_H_
diff --git a/chrome/test/ui/npapi_uitest.cc b/chrome/test/ui/npapi_uitest.cc
index 7826878..3a8905a 100644
--- a/chrome/test/ui/npapi_uitest.cc
+++ b/chrome/test/ui/npapi_uitest.cc
@@ -1,35 +1,6 @@
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-//
-// NPAPI UnitTests.
-//
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
// windows headers
#include <windows.h>
@@ -220,6 +191,17 @@ TEST_F(NPAPIVisiblePluginTester, VerifyPluginWindowRect) {
kTestCompleteSuccess, kShortWaitTimeout);
}
+// Tests that creating a new instance of a plugin while another one is handling
+// a paint message doesn't cause deadlock.
+TEST_F(NPAPIVisiblePluginTester, CreateInstanceInPaint) {
+ show_window_ = true;
+ std::wstring test_case = L"create_instance_in_paint.html";
+ GURL url = GetTestUrl(L"npapi", test_case);
+ NavigateToURL(url);
+ WaitForFinish("create_instance_in_paint", "2", url, kTestCompleteCookie,
+ kTestCompleteSuccess, kShortWaitTimeout);
+}
+
TEST_F(NPAPIVisiblePluginTester, VerifyNPObjectLifetimeTest) {
if (!UITest::in_process_renderer()) {
show_window_ = true;