1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/bind_helpers.h"
6 #include "base/location.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
13 #include "chrome/browser/plugins/plugin_prefs.h"
14 #include "chrome/browser/printing/print_preview_dialog_controller.h"
15 #include "chrome/browser/task_management/task_management_browsertest_util.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_commands.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/common/chrome_content_client.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/grit/generated_resources.h"
22 #include "chrome/test/base/in_process_browser_test.h"
23 #include "chrome/test/base/ui_test_utils.h"
24 #include "components/printing/common/print_messages.h"
25 #include "content/public/browser/plugin_service.h"
26 #include "content/public/browser/render_frame_host.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "ipc/ipc_message_macros.h"
31 #include "ui/base/l10n/l10n_util.h"
34 using content::WebContents
;
35 using content::WebContentsObserver
;
39 class RequestPrintPreviewObserver
: public WebContentsObserver
{
41 explicit RequestPrintPreviewObserver(WebContents
* dialog
)
42 : WebContentsObserver(dialog
) {
44 ~RequestPrintPreviewObserver() override
{}
46 void set_quit_closure(const base::Closure
& quit_closure
) {
47 quit_closure_
= quit_closure
;
51 // content::WebContentsObserver implementation.
52 bool OnMessageReceived(const IPC::Message
& message
) override
{
53 IPC_BEGIN_MESSAGE_MAP(RequestPrintPreviewObserver
, message
)
54 IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview
,
55 OnRequestPrintPreview
)
56 IPC_MESSAGE_UNHANDLED(break;)
57 IPC_END_MESSAGE_MAP();
58 return false; // Report not handled so the real handler receives it.
61 void OnRequestPrintPreview(
62 const PrintHostMsg_RequestPrintPreview_Params
& /* params */) {
63 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, quit_closure_
);
66 base::Closure quit_closure_
;
68 DISALLOW_COPY_AND_ASSIGN(RequestPrintPreviewObserver
);
71 class PrintPreviewDialogClonedObserver
: public WebContentsObserver
{
73 explicit PrintPreviewDialogClonedObserver(WebContents
* dialog
)
74 : WebContentsObserver(dialog
) {
76 ~PrintPreviewDialogClonedObserver() override
{}
78 RequestPrintPreviewObserver
* request_preview_dialog_observer() {
79 return request_preview_dialog_observer_
.get();
83 // content::WebContentsObserver implementation.
84 void DidCloneToNewWebContents(WebContents
* old_web_contents
,
85 WebContents
* new_web_contents
) override
{
86 request_preview_dialog_observer_
.reset(
87 new RequestPrintPreviewObserver(new_web_contents
));
90 scoped_ptr
<RequestPrintPreviewObserver
> request_preview_dialog_observer_
;
92 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogClonedObserver
);
95 class PrintPreviewDialogDestroyedObserver
: public WebContentsObserver
{
97 explicit PrintPreviewDialogDestroyedObserver(WebContents
* dialog
)
98 : WebContentsObserver(dialog
),
99 dialog_destroyed_(false) {
101 ~PrintPreviewDialogDestroyedObserver() override
{}
103 bool dialog_destroyed() const { return dialog_destroyed_
; }
106 // content::WebContentsObserver implementation.
107 void WebContentsDestroyed() override
{ dialog_destroyed_
= true; }
109 bool dialog_destroyed_
;
111 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogDestroyedObserver
);
114 void PluginsLoadedCallback(
115 const base::Closure
& quit_closure
,
116 const std::vector
<content::WebPluginInfo
>& /* info */) {
120 bool GetPdfPluginInfo(content::WebPluginInfo
* info
) {
121 base::FilePath pdf_plugin_path
= base::FilePath::FromUTF8Unsafe(
122 ChromeContentClient::kPDFPluginPath
);
123 return content::PluginService::GetInstance()->GetPluginInfoByPath(
124 pdf_plugin_path
, info
);
127 const char kDummyPrintUrl
[] = "chrome://print/dummy.pdf";
129 void CountFrames(int* frame_count
,
130 content::RenderFrameHost
* frame
) {
134 void CheckPdfPluginForRenderFrame(content::RenderFrameHost
* frame
) {
135 content::WebPluginInfo pdf_plugin_info
;
136 ASSERT_TRUE(GetPdfPluginInfo(&pdf_plugin_info
));
138 ChromePluginServiceFilter
* filter
= ChromePluginServiceFilter::GetInstance();
139 EXPECT_TRUE(filter
->IsPluginAvailable(
140 frame
->GetProcess()->GetID(),
141 frame
->GetRoutingID(),
143 GURL(kDummyPrintUrl
),
150 class PrintPreviewDialogControllerBrowserTest
: public InProcessBrowserTest
{
152 PrintPreviewDialogControllerBrowserTest() : initiator_(nullptr) {}
153 ~PrintPreviewDialogControllerBrowserTest() override
{}
155 WebContents
* initiator() {
159 void PrintPreview() {
160 base::RunLoop run_loop
;
161 request_preview_dialog_observer()->set_quit_closure(run_loop
.QuitClosure());
162 chrome::Print(browser());
166 WebContents
* GetPrintPreviewDialog() {
167 printing::PrintPreviewDialogController
* dialog_controller
=
168 printing::PrintPreviewDialogController::GetInstance();
169 return dialog_controller
->GetPrintPreviewForContents(initiator_
);
173 void SetUpOnMainThread() override
{
174 WebContents
* first_tab
=
175 browser()->tab_strip_model()->GetActiveWebContents();
176 ASSERT_TRUE(first_tab
);
178 // Open a new tab so |cloned_tab_observer_| can see it first and attach a
179 // RequestPrintPreviewObserver to it before the real
180 // PrintPreviewMessageHandler gets created. Thus enabling
181 // RequestPrintPreviewObserver to get messages first for the purposes of
183 cloned_tab_observer_
.reset(new PrintPreviewDialogClonedObserver(first_tab
));
184 chrome::DuplicateTab(browser());
186 initiator_
= browser()->tab_strip_model()->GetActiveWebContents();
187 ASSERT_TRUE(initiator_
);
188 ASSERT_NE(first_tab
, initiator_
);
190 content::PluginService::GetInstance()->Init();
191 content::PluginService::GetInstance()->DisablePluginsDiscoveryForTesting();
194 void TearDownOnMainThread() override
{
195 cloned_tab_observer_
.reset();
196 initiator_
= nullptr;
199 RequestPrintPreviewObserver
* request_preview_dialog_observer() {
200 return cloned_tab_observer_
->request_preview_dialog_observer();
203 scoped_ptr
<PrintPreviewDialogClonedObserver
> cloned_tab_observer_
;
204 WebContents
* initiator_
;
206 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogControllerBrowserTest
);
209 // Test to verify that when a initiator navigates, we can create a new preview
210 // dialog for the new tab contents.
211 // http://crbug.com/377337
213 #define MAYBE_NavigateFromInitiatorTab DISABLED_NavigateFromInitiatorTab
215 #define MAYBE_NavigateFromInitiatorTab NavigateFromInitiatorTab
217 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
218 MAYBE_NavigateFromInitiatorTab
) {
219 // Print for the first time.
222 // Get the preview dialog for the initiator tab.
223 WebContents
* preview_dialog
= GetPrintPreviewDialog();
225 // Check a new print preview dialog got created.
226 ASSERT_TRUE(preview_dialog
);
227 ASSERT_NE(initiator(), preview_dialog
);
229 // Navigate in the initiator tab. Make sure navigating destroys the print
231 PrintPreviewDialogDestroyedObserver
dialog_destroyed_observer(preview_dialog
);
232 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL
));
233 ASSERT_TRUE(dialog_destroyed_observer
.dialog_destroyed());
235 // Try printing again.
238 // Get the print preview dialog for the initiator tab.
239 WebContents
* new_preview_dialog
= GetPrintPreviewDialog();
241 // Check a new preview dialog got created.
242 EXPECT_TRUE(new_preview_dialog
);
245 // Test to verify that after reloading the initiator, it creates a new print
247 // http://crbug.com/377337
249 #define MAYBE_ReloadInitiatorTab DISABLED_ReloadInitiatorTab
251 #define MAYBE_ReloadInitiatorTab ReloadInitiatorTab
253 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
254 MAYBE_ReloadInitiatorTab
) {
255 // Print for the first time.
258 WebContents
* preview_dialog
= GetPrintPreviewDialog();
260 // Check a new print preview dialog got created.
261 ASSERT_TRUE(preview_dialog
);
262 ASSERT_NE(initiator(), preview_dialog
);
264 // Reload the initiator. Make sure reloading destroys the print preview
266 PrintPreviewDialogDestroyedObserver
dialog_destroyed_observer(preview_dialog
);
267 chrome::Reload(browser(), CURRENT_TAB
);
268 content::WaitForLoadStop(
269 browser()->tab_strip_model()->GetActiveWebContents());
270 ASSERT_TRUE(dialog_destroyed_observer
.dialog_destroyed());
272 // Try printing again.
275 // Create a preview dialog for the initiator tab.
276 WebContents
* new_preview_dialog
= GetPrintPreviewDialog();
277 EXPECT_TRUE(new_preview_dialog
);
280 // Test to verify that after print preview works even when the PDF plugin is
281 // disabled for webpages.
282 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
284 // Make sure plugins are loaded.
286 base::RunLoop run_loop
;
287 content::PluginService::GetInstance()->GetPlugins(
288 base::Bind(&PluginsLoadedCallback
, run_loop
.QuitClosure()));
291 // Get the PDF plugin info.
292 content::WebPluginInfo pdf_plugin_info
;
293 ASSERT_TRUE(GetPdfPluginInfo(&pdf_plugin_info
));
295 // Disable the PDF plugin.
296 PluginPrefs::GetForProfile(browser()->profile())->EnablePluginGroup(
297 false, base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName
));
299 // Make sure it is actually disabled for webpages.
300 ChromePluginServiceFilter
* filter
= ChromePluginServiceFilter::GetInstance();
301 content::WebPluginInfo dummy_pdf_plugin_info
= pdf_plugin_info
;
302 EXPECT_FALSE(filter
->IsPluginAvailable(
303 initiator()->GetRenderProcessHost()->GetID(),
304 initiator()->GetMainFrame()->GetRoutingID(),
306 GURL("http://google.com"),
308 &dummy_pdf_plugin_info
));
312 // Check a new print preview dialog got created.
313 WebContents
* preview_dialog
= GetPrintPreviewDialog();
314 ASSERT_TRUE(preview_dialog
);
315 ASSERT_NE(initiator(), preview_dialog
);
317 // Wait until the <iframe> in the print preview renderer has loaded.
318 // |frame_count| should be 2. The other frame is the main frame.
319 const int kExpectedFrameCount
= 2;
322 base::RunLoop run_loop
;
323 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
324 FROM_HERE
, run_loop
.QuitClosure(), base::TimeDelta::FromSeconds(1));
328 preview_dialog
->ForEachFrame(
329 base::Bind(&CountFrames
, base::Unretained(&frame_count
)));
330 } while (frame_count
< kExpectedFrameCount
);
331 ASSERT_EQ(kExpectedFrameCount
, frame_count
);
333 // Make sure all the frames in the dialog has access to the PDF plugin.
334 preview_dialog
->ForEachFrame(base::Bind(&CheckPdfPluginForRenderFrame
));
337 #if defined(ENABLE_TASK_MANAGER)
341 base::string16
GetExpectedPrefix() {
342 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PRINT_PREFIX
,
346 const std::vector
<task_management::WebContentsTag
*>& GetTrackedTags() {
347 return task_management::WebContentsTagsManager::GetInstance()->
351 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
352 TaskManagementTest
) {
353 // This test starts with two tabs open.
354 EXPECT_EQ(2U, GetTrackedTags().size());
357 EXPECT_EQ(3U, GetTrackedTags().size());
359 // Create a task manager and expect the pre-existing print previews are
361 task_management::MockWebContentsTaskManager task_manager
;
362 EXPECT_TRUE(task_manager
.tasks().empty());
363 task_manager
.StartObserving();
364 EXPECT_EQ(3U, task_manager
.tasks().size());
365 const task_management::Task
* pre_existing_task
= task_manager
.tasks().back();
366 EXPECT_EQ(task_management::Task::RENDERER
, pre_existing_task
->GetType());
367 const base::string16 pre_existing_title
= pre_existing_task
->title();
368 const base::string16 expected_prefix
= GetExpectedPrefix();
369 EXPECT_TRUE(base::StartsWith(pre_existing_title
,
371 base::CompareCase::INSENSITIVE_ASCII
));
373 // Navigating away from the current page in the current tab for which a print
374 // preview is displayed will cancel the print preview and hence the task
375 // manger shouldn't show a printing task.
376 ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
377 EXPECT_EQ(2U, GetTrackedTags().size());
378 EXPECT_EQ(2U, task_manager
.tasks().size());
380 // Now start another print preview after the had already been created and
381 // validated that a corresponding task is reported.
383 EXPECT_EQ(3U, GetTrackedTags().size());
384 EXPECT_EQ(3U, task_manager
.tasks().size());
385 const task_management::Task
* task
= task_manager
.tasks().back();
386 EXPECT_EQ(task_management::Task::RENDERER
, task
->GetType());
387 const base::string16 title
= task
->title();
388 EXPECT_TRUE(base::StartsWith(title
,
390 base::CompareCase::INSENSITIVE_ASCII
));
395 #endif // defined(ENABLE_TASK_MANAGER)