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/memory/scoped_ptr.h"
7 #include "base/run_loop.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
10 #include "chrome/browser/plugins/plugin_prefs.h"
11 #include "chrome/browser/printing/print_preview_dialog_controller.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_commands.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/common/chrome_content_client.h"
16 #include "chrome/common/url_constants.h"
17 #include "chrome/test/base/in_process_browser_test.h"
18 #include "chrome/test/base/ui_test_utils.h"
19 #include "components/printing/common/print_messages.h"
20 #include "content/public/browser/plugin_service.h"
21 #include "content/public/browser/render_frame_host.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "ipc/ipc_message_macros.h"
28 using content::WebContents
;
29 using content::WebContentsObserver
;
33 class RequestPrintPreviewObserver
: public WebContentsObserver
{
35 explicit RequestPrintPreviewObserver(WebContents
* dialog
)
36 : WebContentsObserver(dialog
) {
38 ~RequestPrintPreviewObserver() override
{}
40 void set_quit_closure(const base::Closure
& quit_closure
) {
41 quit_closure_
= quit_closure
;
45 // content::WebContentsObserver implementation.
46 bool OnMessageReceived(const IPC::Message
& message
) override
{
47 IPC_BEGIN_MESSAGE_MAP(RequestPrintPreviewObserver
, message
)
48 IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview
,
49 OnRequestPrintPreview
)
50 IPC_MESSAGE_UNHANDLED(break;)
51 IPC_END_MESSAGE_MAP();
52 return false; // Report not handled so the real handler receives it.
55 void OnRequestPrintPreview(
56 const PrintHostMsg_RequestPrintPreview_Params
& /* params */) {
57 base::MessageLoop::current()->PostTask(FROM_HERE
, quit_closure_
);
60 base::Closure quit_closure_
;
62 DISALLOW_COPY_AND_ASSIGN(RequestPrintPreviewObserver
);
65 class PrintPreviewDialogClonedObserver
: public WebContentsObserver
{
67 explicit PrintPreviewDialogClonedObserver(WebContents
* dialog
)
68 : WebContentsObserver(dialog
) {
70 ~PrintPreviewDialogClonedObserver() override
{}
72 RequestPrintPreviewObserver
* request_preview_dialog_observer() {
73 return request_preview_dialog_observer_
.get();
77 // content::WebContentsObserver implementation.
78 void DidCloneToNewWebContents(WebContents
* old_web_contents
,
79 WebContents
* new_web_contents
) override
{
80 request_preview_dialog_observer_
.reset(
81 new RequestPrintPreviewObserver(new_web_contents
));
84 scoped_ptr
<RequestPrintPreviewObserver
> request_preview_dialog_observer_
;
86 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogClonedObserver
);
89 class PrintPreviewDialogDestroyedObserver
: public WebContentsObserver
{
91 explicit PrintPreviewDialogDestroyedObserver(WebContents
* dialog
)
92 : WebContentsObserver(dialog
),
93 dialog_destroyed_(false) {
95 ~PrintPreviewDialogDestroyedObserver() override
{}
97 bool dialog_destroyed() const { return dialog_destroyed_
; }
100 // content::WebContentsObserver implementation.
101 void WebContentsDestroyed() override
{ dialog_destroyed_
= true; }
103 bool dialog_destroyed_
;
105 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogDestroyedObserver
);
108 void PluginsLoadedCallback(
109 const base::Closure
& quit_closure
,
110 const std::vector
<content::WebPluginInfo
>& /* info */) {
114 bool GetPdfPluginInfo(content::WebPluginInfo
* info
) {
115 base::FilePath pdf_plugin_path
= base::FilePath::FromUTF8Unsafe(
116 ChromeContentClient::kPDFPluginPath
);
117 return content::PluginService::GetInstance()->GetPluginInfoByPath(
118 pdf_plugin_path
, info
);
121 const char kDummyPrintUrl
[] = "chrome://print/dummy.pdf";
123 void CountFrames(int* frame_count
,
124 content::RenderFrameHost
* frame
) {
128 void CheckPdfPluginForRenderFrame(content::RenderFrameHost
* frame
) {
129 content::WebPluginInfo pdf_plugin_info
;
130 ASSERT_TRUE(GetPdfPluginInfo(&pdf_plugin_info
));
132 ChromePluginServiceFilter
* filter
= ChromePluginServiceFilter::GetInstance();
133 EXPECT_TRUE(filter
->IsPluginAvailable(
134 frame
->GetProcess()->GetID(),
135 frame
->GetRoutingID(),
137 GURL(kDummyPrintUrl
),
144 class PrintPreviewDialogControllerBrowserTest
: public InProcessBrowserTest
{
146 PrintPreviewDialogControllerBrowserTest() : initiator_(NULL
) {}
147 ~PrintPreviewDialogControllerBrowserTest() override
{}
149 WebContents
* initiator() {
153 void PrintPreview() {
154 base::RunLoop run_loop
;
155 request_preview_dialog_observer()->set_quit_closure(run_loop
.QuitClosure());
156 chrome::Print(browser());
160 WebContents
* GetPrintPreviewDialog() {
161 printing::PrintPreviewDialogController
* dialog_controller
=
162 printing::PrintPreviewDialogController::GetInstance();
163 return dialog_controller
->GetPrintPreviewForContents(initiator_
);
167 void SetUpOnMainThread() override
{
168 WebContents
* first_tab
=
169 browser()->tab_strip_model()->GetActiveWebContents();
170 ASSERT_TRUE(first_tab
);
172 // Open a new tab so |cloned_tab_observer_| can see it first and attach a
173 // RequestPrintPreviewObserver to it before the real
174 // PrintPreviewMessageHandler gets created. Thus enabling
175 // RequestPrintPreviewObserver to get messages first for the purposes of
177 cloned_tab_observer_
.reset(new PrintPreviewDialogClonedObserver(first_tab
));
178 chrome::DuplicateTab(browser());
180 initiator_
= browser()->tab_strip_model()->GetActiveWebContents();
181 ASSERT_TRUE(initiator_
);
182 ASSERT_NE(first_tab
, initiator_
);
184 content::PluginService::GetInstance()->Init();
185 content::PluginService::GetInstance()->DisablePluginsDiscoveryForTesting();
188 void TearDownOnMainThread() override
{
189 cloned_tab_observer_
.reset();
193 RequestPrintPreviewObserver
* request_preview_dialog_observer() {
194 return cloned_tab_observer_
->request_preview_dialog_observer();
197 scoped_ptr
<PrintPreviewDialogClonedObserver
> cloned_tab_observer_
;
198 WebContents
* initiator_
;
200 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogControllerBrowserTest
);
203 // Test to verify that when a initiator navigates, we can create a new preview
204 // dialog for the new tab contents.
205 // http://crbug.com/377337
207 #define MAYBE_NavigateFromInitiatorTab DISABLED_NavigateFromInitiatorTab
209 #define MAYBE_NavigateFromInitiatorTab NavigateFromInitiatorTab
211 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
212 MAYBE_NavigateFromInitiatorTab
) {
213 // Print for the first time.
216 // Get the preview dialog for the initiator tab.
217 WebContents
* preview_dialog
= GetPrintPreviewDialog();
219 // Check a new print preview dialog got created.
220 ASSERT_TRUE(preview_dialog
);
221 ASSERT_NE(initiator(), preview_dialog
);
223 // Navigate in the initiator tab. Make sure navigating destroys the print
225 PrintPreviewDialogDestroyedObserver
dialog_destroyed_observer(preview_dialog
);
226 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL
));
227 ASSERT_TRUE(dialog_destroyed_observer
.dialog_destroyed());
229 // Try printing again.
232 // Get the print preview dialog for the initiator tab.
233 WebContents
* new_preview_dialog
= GetPrintPreviewDialog();
235 // Check a new preview dialog got created.
236 EXPECT_TRUE(new_preview_dialog
);
239 // Test to verify that after reloading the initiator, it creates a new print
241 // http://crbug.com/377337
243 #define MAYBE_ReloadInitiatorTab DISABLED_ReloadInitiatorTab
245 #define MAYBE_ReloadInitiatorTab ReloadInitiatorTab
247 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
248 MAYBE_ReloadInitiatorTab
) {
249 // Print for the first time.
252 WebContents
* preview_dialog
= GetPrintPreviewDialog();
254 // Check a new print preview dialog got created.
255 ASSERT_TRUE(preview_dialog
);
256 ASSERT_NE(initiator(), preview_dialog
);
258 // Reload the initiator. Make sure reloading destroys the print preview
260 PrintPreviewDialogDestroyedObserver
dialog_destroyed_observer(preview_dialog
);
261 chrome::Reload(browser(), CURRENT_TAB
);
262 content::WaitForLoadStop(
263 browser()->tab_strip_model()->GetActiveWebContents());
264 ASSERT_TRUE(dialog_destroyed_observer
.dialog_destroyed());
266 // Try printing again.
269 // Create a preview dialog for the initiator tab.
270 WebContents
* new_preview_dialog
= GetPrintPreviewDialog();
271 EXPECT_TRUE(new_preview_dialog
);
274 // Test to verify that after print preview works even when the PDF plugin is
275 // disabled for webpages.
276 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest
,
278 // Make sure plugins are loaded.
280 base::RunLoop run_loop
;
281 content::PluginService::GetInstance()->GetPlugins(
282 base::Bind(&PluginsLoadedCallback
, run_loop
.QuitClosure()));
285 // Get the PDF plugin info.
286 content::WebPluginInfo pdf_plugin_info
;
287 ASSERT_TRUE(GetPdfPluginInfo(&pdf_plugin_info
));
289 // Disable the PDF plugin.
290 PluginPrefs::GetForProfile(browser()->profile())->EnablePluginGroup(
291 false, base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName
));
293 // Make sure it is actually disabled for webpages.
294 ChromePluginServiceFilter
* filter
= ChromePluginServiceFilter::GetInstance();
295 content::WebPluginInfo dummy_pdf_plugin_info
= pdf_plugin_info
;
296 EXPECT_FALSE(filter
->IsPluginAvailable(
297 initiator()->GetRenderProcessHost()->GetID(),
298 initiator()->GetMainFrame()->GetRoutingID(),
300 GURL("http://google.com"),
302 &dummy_pdf_plugin_info
));
306 // Check a new print preview dialog got created.
307 WebContents
* preview_dialog
= GetPrintPreviewDialog();
308 ASSERT_TRUE(preview_dialog
);
309 ASSERT_NE(initiator(), preview_dialog
);
311 // Wait until the <iframe> in the print preview renderer has loaded.
312 // |frame_count| should be 2. The other frame is the main frame.
313 const int kExpectedFrameCount
= 2;
316 base::RunLoop run_loop
;
317 base::MessageLoop::current()->PostDelayedTask(
318 FROM_HERE
, run_loop
.QuitClosure(), base::TimeDelta::FromSeconds(1));
322 preview_dialog
->ForEachFrame(
323 base::Bind(&CountFrames
, base::Unretained(&frame_count
)));
324 } while (frame_count
< kExpectedFrameCount
);
325 ASSERT_EQ(kExpectedFrameCount
, frame_count
);
327 // Make sure all the frames in the dialog has access to the PDF plugin.
328 preview_dialog
->ForEachFrame(base::Bind(&CheckPdfPluginForRenderFrame
));