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/ui/browser.h"
16 #include "chrome/browser/ui/browser_commands.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/common/chrome_content_client.h"
19 #include "chrome/common/url_constants.h"
20 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "components/printing/common/print_messages.h"
23 #include "content/public/browser/plugin_service.h"
24 #include "content/public/browser/render_frame_host.h"
25 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/web_contents_observer.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "ipc/ipc_message_macros.h"
31 using content::WebContents
;
32 using content::WebContentsObserver
;
36 class RequestPrintPreviewObserver
: public WebContentsObserver
{
38 explicit RequestPrintPreviewObserver(WebContents
* dialog
)
39 : WebContentsObserver(dialog
) {
41 ~RequestPrintPreviewObserver() override
{}
43 void set_quit_closure(const base::Closure
& quit_closure
) {
44 quit_closure_
= quit_closure
;
48 // content::WebContentsObserver implementation.
49 bool OnMessageReceived(const IPC::Message
& message
) override
{
50 IPC_BEGIN_MESSAGE_MAP(RequestPrintPreviewObserver
, message
)
51 IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview
,
52 OnRequestPrintPreview
)
53 IPC_MESSAGE_UNHANDLED(break;)
54 IPC_END_MESSAGE_MAP();
55 return false; // Report not handled so the real handler receives it.
58 void OnRequestPrintPreview(
59 const PrintHostMsg_RequestPrintPreview_Params
& /* params */) {
60 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, quit_closure_
);
63 base::Closure quit_closure_
;
65 DISALLOW_COPY_AND_ASSIGN(RequestPrintPreviewObserver
);
68 class PrintPreviewDialogClonedObserver
: public WebContentsObserver
{
70 explicit PrintPreviewDialogClonedObserver(WebContents
* dialog
)
71 : WebContentsObserver(dialog
) {
73 ~PrintPreviewDialogClonedObserver() override
{}
75 RequestPrintPreviewObserver
* request_preview_dialog_observer() {
76 return request_preview_dialog_observer_
.get();
80 // content::WebContentsObserver implementation.
81 void DidCloneToNewWebContents(WebContents
* old_web_contents
,
82 WebContents
* new_web_contents
) override
{
83 request_preview_dialog_observer_
.reset(
84 new RequestPrintPreviewObserver(new_web_contents
));
87 scoped_ptr
<RequestPrintPreviewObserver
> request_preview_dialog_observer_
;
89 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogClonedObserver
);
92 class PrintPreviewDialogDestroyedObserver
: public WebContentsObserver
{
94 explicit PrintPreviewDialogDestroyedObserver(WebContents
* dialog
)
95 : WebContentsObserver(dialog
),
96 dialog_destroyed_(false) {
98 ~PrintPreviewDialogDestroyedObserver() override
{}
100 bool dialog_destroyed() const { return dialog_destroyed_
; }
103 // content::WebContentsObserver implementation.
104 void WebContentsDestroyed() override
{ dialog_destroyed_
= true; }
106 bool dialog_destroyed_
;
108 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogDestroyedObserver
);
111 void PluginsLoadedCallback(
112 const base::Closure
& quit_closure
,
113 const std::vector
<content::WebPluginInfo
>& /* info */) {
117 bool GetPdfPluginInfo(content::WebPluginInfo
* info
) {
118 base::FilePath pdf_plugin_path
= base::FilePath::FromUTF8Unsafe(
119 ChromeContentClient::kPDFPluginPath
);
120 return content::PluginService::GetInstance()->GetPluginInfoByPath(
121 pdf_plugin_path
, info
);
124 const char kDummyPrintUrl
[] = "chrome://print/dummy.pdf";
126 void CountFrames(int* frame_count
,
127 content::RenderFrameHost
* frame
) {
131 void CheckPdfPluginForRenderFrame(content::RenderFrameHost
* frame
) {
132 content::WebPluginInfo pdf_plugin_info
;
133 ASSERT_TRUE(GetPdfPluginInfo(&pdf_plugin_info
));
135 ChromePluginServiceFilter
* filter
= ChromePluginServiceFilter::GetInstance();
136 EXPECT_TRUE(filter
->IsPluginAvailable(
137 frame
->GetProcess()->GetID(),
138 frame
->GetRoutingID(),
140 GURL(kDummyPrintUrl
),
147 class PrintPreviewDialogControllerBrowserTest
: public InProcessBrowserTest
{
149 PrintPreviewDialogControllerBrowserTest() : initiator_(nullptr) {}
150 ~PrintPreviewDialogControllerBrowserTest() override
{}
152 WebContents
* initiator() {
156 void PrintPreview() {
157 base::RunLoop run_loop
;
158 request_preview_dialog_observer()->set_quit_closure(run_loop
.QuitClosure());
159 chrome::Print(browser());
163 WebContents
* GetPrintPreviewDialog() {
164 printing::PrintPreviewDialogController
* dialog_controller
=
165 printing::PrintPreviewDialogController::GetInstance();
166 return dialog_controller
->GetPrintPreviewForContents(initiator_
);
170 void SetUpOnMainThread() override
{
171 WebContents
* first_tab
=
172 browser()->tab_strip_model()->GetActiveWebContents();
173 ASSERT_TRUE(first_tab
);
175 // Open a new tab so |cloned_tab_observer_| can see it first and attach a
176 // RequestPrintPreviewObserver to it before the real
177 // PrintPreviewMessageHandler gets created. Thus enabling
178 // RequestPrintPreviewObserver to get messages first for the purposes of
180 cloned_tab_observer_
.reset(new PrintPreviewDialogClonedObserver(first_tab
));
181 chrome::DuplicateTab(browser());
183 initiator_
= browser()->tab_strip_model()->GetActiveWebContents();
184 ASSERT_TRUE(initiator_
);
185 ASSERT_NE(first_tab
, initiator_
);
187 content::PluginService::GetInstance()->Init();
188 content::PluginService::GetInstance()->DisablePluginsDiscoveryForTesting();
191 void TearDownOnMainThread() override
{
192 cloned_tab_observer_
.reset();
193 initiator_
= nullptr;
196 RequestPrintPreviewObserver
* request_preview_dialog_observer() {
197 return cloned_tab_observer_
->request_preview_dialog_observer();
200 scoped_ptr
<PrintPreviewDialogClonedObserver
> cloned_tab_observer_
;
201 WebContents
* initiator_
;
203 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogControllerBrowserTest
);
206 // Test to verify that when a initiator navigates, we can create a new preview
207 // dialog for the new tab contents.
208 // http://crbug.com/377337
210 #define MAYBE_NavigateFromInitiatorTab DISABLED_NavigateFromInitiatorTab
212 #define MAYBE_NavigateFromInitiatorTab NavigateFromInitiatorTab
214 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
215 MAYBE_NavigateFromInitiatorTab
) {
216 // Print for the first time.
219 // Get the preview dialog for the initiator tab.
220 WebContents
* preview_dialog
= GetPrintPreviewDialog();
222 // Check a new print preview dialog got created.
223 ASSERT_TRUE(preview_dialog
);
224 ASSERT_NE(initiator(), preview_dialog
);
226 // Navigate in the initiator tab. Make sure navigating destroys the print
228 PrintPreviewDialogDestroyedObserver
dialog_destroyed_observer(preview_dialog
);
229 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL
));
230 ASSERT_TRUE(dialog_destroyed_observer
.dialog_destroyed());
232 // Try printing again.
235 // Get the print preview dialog for the initiator tab.
236 WebContents
* new_preview_dialog
= GetPrintPreviewDialog();
238 // Check a new preview dialog got created.
239 EXPECT_TRUE(new_preview_dialog
);
242 // Test to verify that after reloading the initiator, it creates a new print
244 // http://crbug.com/377337
246 #define MAYBE_ReloadInitiatorTab DISABLED_ReloadInitiatorTab
248 #define MAYBE_ReloadInitiatorTab ReloadInitiatorTab
250 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
251 MAYBE_ReloadInitiatorTab
) {
252 // Print for the first time.
255 WebContents
* preview_dialog
= GetPrintPreviewDialog();
257 // Check a new print preview dialog got created.
258 ASSERT_TRUE(preview_dialog
);
259 ASSERT_NE(initiator(), preview_dialog
);
261 // Reload the initiator. Make sure reloading destroys the print preview
263 PrintPreviewDialogDestroyedObserver
dialog_destroyed_observer(preview_dialog
);
264 chrome::Reload(browser(), CURRENT_TAB
);
265 content::WaitForLoadStop(
266 browser()->tab_strip_model()->GetActiveWebContents());
267 ASSERT_TRUE(dialog_destroyed_observer
.dialog_destroyed());
269 // Try printing again.
272 // Create a preview dialog for the initiator tab.
273 WebContents
* new_preview_dialog
= GetPrintPreviewDialog();
274 EXPECT_TRUE(new_preview_dialog
);
277 // Test to verify that after print preview works even when the PDF plugin is
278 // disabled for webpages.
279 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
281 // Make sure plugins are loaded.
283 base::RunLoop run_loop
;
284 content::PluginService::GetInstance()->GetPlugins(
285 base::Bind(&PluginsLoadedCallback
, run_loop
.QuitClosure()));
288 // Get the PDF plugin info.
289 content::WebPluginInfo pdf_plugin_info
;
290 ASSERT_TRUE(GetPdfPluginInfo(&pdf_plugin_info
));
292 // Disable the PDF plugin.
293 PluginPrefs::GetForProfile(browser()->profile())->EnablePluginGroup(
294 false, base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName
));
296 // Make sure it is actually disabled for webpages.
297 ChromePluginServiceFilter
* filter
= ChromePluginServiceFilter::GetInstance();
298 content::WebPluginInfo dummy_pdf_plugin_info
= pdf_plugin_info
;
299 EXPECT_FALSE(filter
->IsPluginAvailable(
300 initiator()->GetRenderProcessHost()->GetID(),
301 initiator()->GetMainFrame()->GetRoutingID(),
303 GURL("http://google.com"),
305 &dummy_pdf_plugin_info
));
309 // Check a new print preview dialog got created.
310 WebContents
* preview_dialog
= GetPrintPreviewDialog();
311 ASSERT_TRUE(preview_dialog
);
312 ASSERT_NE(initiator(), preview_dialog
);
314 // Wait until the <iframe> in the print preview renderer has loaded.
315 // |frame_count| should be 2. The other frame is the main frame.
316 const int kExpectedFrameCount
= 2;
319 base::RunLoop run_loop
;
320 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
321 FROM_HERE
, run_loop
.QuitClosure(), base::TimeDelta::FromSeconds(1));
325 preview_dialog
->ForEachFrame(
326 base::Bind(&CountFrames
, base::Unretained(&frame_count
)));
327 } while (frame_count
< kExpectedFrameCount
);
328 ASSERT_EQ(kExpectedFrameCount
, frame_count
);
330 // Make sure all the frames in the dialog has access to the PDF plugin.
331 preview_dialog
->ForEachFrame(base::Bind(&CheckPdfPluginForRenderFrame
));