diff options
Diffstat (limited to 'chromium/chrome/browser/printing/print_browsertest.cc')
-rw-r--r-- | chromium/chrome/browser/printing/print_browsertest.cc | 316 |
1 files changed, 228 insertions, 88 deletions
diff --git a/chromium/chrome/browser/printing/print_browsertest.cc b/chromium/chrome/browser/printing/print_browsertest.cc index 3de2b60a683..cc9c1fde80c 100644 --- a/chromium/chrome/browser/printing/print_browsertest.cc +++ b/chromium/chrome/browser/printing/print_browsertest.cc @@ -27,6 +27,7 @@ #include "components/prefs/pref_service.h" #include "components/printing/browser/print_composite_client.h" #include "components/printing/browser/print_manager_utils.h" +#include "components/printing/common/print.mojom-test-utils.h" #include "components/printing/common/print.mojom.h" #include "components/printing/common/print_messages.h" #include "content/public/browser/browser_message_filter.h" @@ -41,6 +42,7 @@ #include "mojo/public/cpp/bindings/associated_remote.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "printing/mojom/print.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h" @@ -78,6 +80,8 @@ class PrintPreviewObserver : PrintPreviewUI::TestDelegate { } } + content::WebContents* GetPrintPreviewDialog() { return preview_dialog_; } + private: // PrintPreviewUI::TestDelegate: void DidGetPreviewPageCount(int page_count) override { @@ -90,6 +94,7 @@ class PrintPreviewObserver : PrintPreviewUI::TestDelegate { CHECK(rendered_page_count_ <= total_page_count_); if (rendered_page_count_ == total_page_count_ && run_loop_) { run_loop_->Quit(); + preview_dialog_ = preview_dialog; if (queue_.has_value()) { content::ExecuteScriptAsync( @@ -106,6 +111,7 @@ class PrintPreviewObserver : PrintPreviewUI::TestDelegate { base::Optional<content::DOMMessageQueue> queue_; int total_page_count_ = 1; int rendered_page_count_ = 0; + content::WebContents* preview_dialog_ = nullptr; base::RunLoop* run_loop_ = nullptr; DISALLOW_COPY_AND_ASSIGN(PrintPreviewObserver); @@ -129,8 +135,8 @@ class NupPrintingTestDelegate : public PrintingMessageFilter::TestDelegate { params.dpi = gfx::Size(72, 72); params.document_cookie = kDefaultDocumentCookie; params.pages_per_sheet = 4; - params.printed_doc_type = - IsOopifEnabled() ? SkiaDocumentType::MSKP : SkiaDocumentType::PDF; + params.printed_doc_type = IsOopifEnabled() ? mojom::SkiaDocumentType::kMSKP + : mojom::SkiaDocumentType::kPDF; return params; } @@ -138,66 +144,127 @@ class NupPrintingTestDelegate : public PrintingMessageFilter::TestDelegate { DISALLOW_COPY_AND_ASSIGN(NupPrintingTestDelegate); }; -class TestPrintFrameContentMsgFilter : public content::BrowserMessageFilter { +class TestPrintRenderFrame + : public mojom::PrintRenderFrameInterceptorForTesting { public: - TestPrintFrameContentMsgFilter(int document_cookie, - base::RepeatingClosure msg_callback) - : content::BrowserMessageFilter(PrintMsgStart), + TestPrintRenderFrame(content::RenderFrameHost* frame_host, + content::WebContents* web_contents, + int document_cookie, + base::RepeatingClosure msg_callback) + : frame_host_(frame_host), + web_contents_(web_contents), document_cookie_(document_cookie), task_runner_(base::SequencedTaskRunnerHandle::Get()), msg_callback_(msg_callback) {} + ~TestPrintRenderFrame() override = default; - bool OnMessageReceived(const IPC::Message& message) override { - // Only expect PrintHostMsg_DidPrintFrameContent message. - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(TestPrintFrameContentMsgFilter, message) - IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintFrameContent, CheckMessage) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - EXPECT_TRUE(handled); + void OnDidPrintFrameContent(int document_cookie, + mojom::DidPrintContentParamsPtr param, + PrintFrameContentCallback callback) const { + EXPECT_EQ(document_cookie, document_cookie_); + ASSERT_TRUE(param->metafile_data_region.IsValid()); + EXPECT_GT(param->metafile_data_region.GetSize(), 0U); task_runner_->PostTask(FROM_HERE, msg_callback_); - return true; - } - - private: - ~TestPrintFrameContentMsgFilter() override = default; + std::move(callback).Run(document_cookie, std::move(param)); + } + + void Bind(mojo::ScopedInterfaceEndpointHandle handle) { + receiver_.Bind(mojo::PendingAssociatedReceiver<mojom::PrintRenderFrame>( + std::move(handle))); + } + + // mojom::PrintRenderFrameInterceptorForTesting + mojom::PrintRenderFrame* GetForwardingInterface() override { + NOTREACHED(); + return nullptr; + } + void PrintFrameContent(mojom::PrintFrameContentParamsPtr params, + PrintFrameContentCallback callback) override { + // Sends the printed result back. + mojom::DidPrintContentParamsPtr printed_frame_params = + mojom::DidPrintContentParams::New(); + // Creates a small amount of region to avoid passing empty data to mojo. + constexpr size_t kSize = 10; + base::MappedReadOnlyRegion region_mapping = + base::ReadOnlySharedMemoryRegion::Create(kSize); + printed_frame_params->metafile_data_region = + std::move(region_mapping.region); + OnDidPrintFrameContent(params->document_cookie, + std::move(printed_frame_params), + std::move(callback)); + + auto* client = PrintCompositeClient::FromWebContents(web_contents_); + if (!client) + return; - void CheckMessage(int document_cookie, - const PrintHostMsg_DidPrintContent_Params& param) { - EXPECT_EQ(document_cookie, document_cookie_); - ASSERT_TRUE(param.metafile_data_region.IsValid()); - EXPECT_GT(param.metafile_data_region.GetSize(), 0U); + // Prints its children. + content::RenderFrameHost* child = ChildFrameAt(frame_host_, 0); + for (size_t i = 1; child; i++) { + if (child->GetSiteInstance() != frame_host_->GetSiteInstance()) { + client->PrintCrossProcessSubframe(gfx::Rect(), params->document_cookie, + child); + } + child = ChildFrameAt(frame_host_, i); + } } + private: + content::RenderFrameHost* frame_host_; + content::WebContents* web_contents_; const int document_cookie_; scoped_refptr<base::SequencedTaskRunner> task_runner_; base::RepeatingClosure msg_callback_; + mojo::AssociatedReceiver<mojom::PrintRenderFrame> receiver_{this}; }; -class KillPrintFrameContentMsgFilter : public content::BrowserMessageFilter { +class KillPrintRenderFrame + : public mojom::PrintRenderFrameInterceptorForTesting { public: - explicit KillPrintFrameContentMsgFilter(content::RenderProcessHost* rph) - : content::BrowserMessageFilter(PrintMsgStart), rph_(rph) {} + explicit KillPrintRenderFrame(content::RenderProcessHost* rph) : rph_(rph) {} + ~KillPrintRenderFrame() override = default; - bool OnMessageReceived(const IPC::Message& message) override { - // Only handle PrintHostMsg_DidPrintFrameContent message. - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(KillPrintFrameContentMsgFilter, message) - IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintFrameContent, KillRenderProcess) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; + void OverrideBinderForTesting(content::RenderFrameHost* render_frame_host) { + render_frame_host->GetRemoteAssociatedInterfaces() + ->OverrideBinderForTesting( + mojom::PrintRenderFrame::Name_, + base::BindRepeating(&KillPrintRenderFrame::Bind, + base::Unretained(this))); } - private: - ~KillPrintFrameContentMsgFilter() override = default; - void KillRenderProcess(int document_cookie, - const PrintHostMsg_DidPrintContent_Params& param) { + mojom::DidPrintContentParamsPtr param, + PrintFrameContentCallback callback) const { + std::move(callback).Run(document_cookie, std::move(param)); rph_->Shutdown(0); } - content::RenderProcessHost* rph_; + void Bind(mojo::ScopedInterfaceEndpointHandle handle) { + receiver_.Bind(mojo::PendingAssociatedReceiver<mojom::PrintRenderFrame>( + std::move(handle))); + } + + // mojom::PrintRenderFrameInterceptorForTesting + mojom::PrintRenderFrame* GetForwardingInterface() override { + NOTREACHED(); + return nullptr; + } + void PrintFrameContent(mojom::PrintFrameContentParamsPtr params, + PrintFrameContentCallback callback) override { + // Sends the printed result back. + const size_t kSize = 10; + mojom::DidPrintContentParamsPtr printed_frame_params = + mojom::DidPrintContentParams::New(); + base::MappedReadOnlyRegion region_mapping = + base::ReadOnlySharedMemoryRegion::Create(kSize); + printed_frame_params->metafile_data_region = + std::move(region_mapping.region); + KillRenderProcess(params->document_cookie, std::move(printed_frame_params), + std::move(callback)); + } + + private: + content::RenderProcessHost* const rph_; + mojo::AssociatedReceiver<mojom::PrintRenderFrame> receiver_{this}; }; } // namespace @@ -210,7 +277,6 @@ class PrintBrowserTest : public InProcessBrowserTest { void SetUp() override { num_expected_messages_ = 1; // By default, only wait on one message. num_received_messages_ = 0; - run_loop_.reset(); InProcessBrowserTest::SetUp(); } @@ -246,23 +312,27 @@ class PrintBrowserTest : public InProcessBrowserTest { num_expected_messages_ = num; } - void WaitUntilMessagesReceived() { - run_loop_ = std::make_unique<base::RunLoop>(); - run_loop_->Run(); + void WaitUntilCallbackReceived() { + base::RunLoop run_loop; + quit_callback_ = run_loop.QuitClosure(); + run_loop.Run(); } void CheckForQuit() { - if (++num_received_messages_ == num_expected_messages_) { - run_loop_->QuitWhenIdle(); - } + if (++num_received_messages_ != num_expected_messages_) + return; + if (quit_callback_) + std::move(quit_callback_).Run(); } - void AddFilterForFrame(content::RenderFrameHost* frame_host) { - auto filter = base::MakeRefCounted<TestPrintFrameContentMsgFilter>( - kDefaultDocumentCookie, - base::BindRepeating(&PrintBrowserTest::CheckForQuit, - base::Unretained(this))); - frame_host->GetProcess()->AddFilter(filter.get()); + void CreateTestPrintRenderFrame(content::RenderFrameHost* frame_host, + content::WebContents* web_contents) { + frame_content_.emplace( + frame_host, std::make_unique<TestPrintRenderFrame>( + frame_host, web_contents, kDefaultDocumentCookie, + base::BindRepeating(&PrintBrowserTest::CheckForQuit, + base::Unretained(this)))); + OverrideBinderForTesting(frame_host); } static mojom::PrintFrameContentParamsPtr GetDefaultPrintFrameParams() { @@ -270,17 +340,34 @@ class PrintBrowserTest : public InProcessBrowserTest { kDefaultDocumentCookie); } - static const mojo::AssociatedRemote<mojom::PrintRenderFrame> - GetPrintRenderFrame(content::RenderFrameHost* rfh) { - mojo::AssociatedRemote<mojom::PrintRenderFrame> remote; - rfh->GetRemoteAssociatedInterfaces()->GetInterface(&remote); - return remote; + const mojo::AssociatedRemote<mojom::PrintRenderFrame>& GetPrintRenderFrame( + content::RenderFrameHost* rfh) { + if (!remote_) + rfh->GetRemoteAssociatedInterfaces()->GetInterface(&remote_); + return remote_; } private: + TestPrintRenderFrame* GetFrameContent(content::RenderFrameHost* host) const { + auto iter = frame_content_.find(host); + return iter != frame_content_.end() ? iter->second.get() : nullptr; + } + + void OverrideBinderForTesting(content::RenderFrameHost* render_frame_host) { + render_frame_host->GetRemoteAssociatedInterfaces() + ->OverrideBinderForTesting( + mojom::PrintRenderFrame::Name_, + base::BindRepeating( + &TestPrintRenderFrame::Bind, + base::Unretained(GetFrameContent(render_frame_host)))); + } + unsigned int num_expected_messages_; unsigned int num_received_messages_; - std::unique_ptr<base::RunLoop> run_loop_; + base::OnceClosure quit_callback_; + mojo::AssociatedRemote<mojom::PrintRenderFrame> remote_; + std::map<content::RenderFrameHost*, std::unique_ptr<TestPrintRenderFrame>> + frame_content_; }; class SitePerProcessPrintBrowserTest : public PrintBrowserTest { @@ -444,7 +531,7 @@ IN_PROC_BROWSER_TEST_F(PrintBrowserTest, SelectionContainsIframe) { // Printing frame content for the main frame of a generic webpage. // This test passes when the printed result is sent back and checked in -// TestPrintFrameContentMsgFilter::CheckMessage(). +// TestPrintRenderFrame::OnDidPrintFrameContent(). IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintFrameContent) { ASSERT_TRUE(embedded_test_server()->Started()); GURL url(embedded_test_server()->GetURL("/printing/test1.html")); @@ -453,18 +540,18 @@ IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintFrameContent) { content::WebContents* original_contents = browser()->tab_strip_model()->GetActiveWebContents(); content::RenderFrameHost* rfh = original_contents->GetMainFrame(); - AddFilterForFrame(rfh); - - GetPrintRenderFrame(rfh)->PrintFrameContent(GetDefaultPrintFrameParams()); + CreateTestPrintRenderFrame(rfh, original_contents); + GetPrintRenderFrame(rfh)->PrintFrameContent(GetDefaultPrintFrameParams(), + base::DoNothing()); // The printed result will be received and checked in - // TestPrintFrameContentMsgFilter. - WaitUntilMessagesReceived(); + // TestPrintRenderFrame. + WaitUntilCallbackReceived(); } // Printing frame content for a cross-site iframe. // This test passes when the iframe responds to the print message. -// The response is checked in TestPrintFrameContentMsgFilter::CheckMessage(). +// The response is checked in TestPrintRenderFrame::OnDidPrintFrameContent(). IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintSubframeContent) { ASSERT_TRUE(embedded_test_server()->Started()); GURL url( @@ -477,21 +564,20 @@ IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintSubframeContent) { content::RenderFrameHost* test_frame = original_contents->GetAllFrames()[1]; ASSERT_TRUE(test_frame); - AddFilterForFrame(test_frame); - + CreateTestPrintRenderFrame(test_frame, original_contents); GetPrintRenderFrame(test_frame) - ->PrintFrameContent(GetDefaultPrintFrameParams()); + ->PrintFrameContent(GetDefaultPrintFrameParams(), base::DoNothing()); // The printed result will be received and checked in - // TestPrintFrameContentMsgFilter. - WaitUntilMessagesReceived(); + // TestPrintRenderFrame. + WaitUntilCallbackReceived(); } // Printing frame content with a cross-site iframe which also has a cross-site // iframe. The site reference chain is a.com --> b.com --> c.com. // This test passes when both cross-site frames are printed and their // responses which are checked in -// TestPrintFrameContentMsgFilter::CheckMessage(). +// TestPrintRenderFrame::OnDidPrintFrameContent(). IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintSubframeChain) { ASSERT_TRUE(embedded_test_server()->Started()); GURL url(embedded_test_server()->GetURL( @@ -518,19 +604,19 @@ IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintSubframeChain) { ASSERT_NE(grandchild_frame->GetProcess(), main_frame->GetProcess()); } - AddFilterForFrame(main_frame); + CreateTestPrintRenderFrame(main_frame, original_contents); if (oopif_enabled) { - AddFilterForFrame(child_frame); - AddFilterForFrame(grandchild_frame); + CreateTestPrintRenderFrame(child_frame, original_contents); + CreateTestPrintRenderFrame(grandchild_frame, original_contents); } GetPrintRenderFrame(main_frame) - ->PrintFrameContent(GetDefaultPrintFrameParams()); + ->PrintFrameContent(GetDefaultPrintFrameParams(), base::DoNothing()); // The printed result will be received and checked in - // TestPrintFrameContentMsgFilter. + // TestPrintRenderFrame. SetNumExpectedMessages(oopif_enabled ? 3 : 1); - WaitUntilMessagesReceived(); + WaitUntilCallbackReceived(); } // Printing frame content with a cross-site iframe who also has a cross site @@ -538,7 +624,7 @@ IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintSubframeChain) { // The site reference loop is a.com --> b.com --> a.com. // This test passes when both cross-site frames are printed and send back // responses which are checked in -// TestPrintFrameContentMsgFilter::CheckMessage(). +// TestPrintRenderFrame::OnDidPrintFrameContent(). IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintSubframeABA) { ASSERT_TRUE(embedded_test_server()->Started()); GURL url(embedded_test_server()->GetURL( @@ -564,17 +650,19 @@ IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintSubframeABA) { // enabled, they will be in the same process. ASSERT_EQ(grandchild_frame->GetProcess(), main_frame->GetProcess()); - AddFilterForFrame(main_frame); - if (oopif_enabled) - AddFilterForFrame(child_frame); + CreateTestPrintRenderFrame(main_frame, original_contents); + if (oopif_enabled) { + CreateTestPrintRenderFrame(child_frame, original_contents); + CreateTestPrintRenderFrame(grandchild_frame, original_contents); + } GetPrintRenderFrame(main_frame) - ->PrintFrameContent(GetDefaultPrintFrameParams()); + ->PrintFrameContent(GetDefaultPrintFrameParams(), base::DoNothing()); // The printed result will be received and checked in - // TestPrintFrameContentMsgFilter. + // TestPrintRenderFrame. SetNumExpectedMessages(oopif_enabled ? 3 : 1); - WaitUntilMessagesReceived(); + WaitUntilCallbackReceived(); } // Printing preview a simple webpage when site per process is enabled. @@ -635,10 +723,9 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessPrintBrowserTest, ASSERT_TRUE(subframe); auto* subframe_rph = subframe->GetProcess(); - auto filter = - base::MakeRefCounted<KillPrintFrameContentMsgFilter>(subframe_rph); + KillPrintRenderFrame frame_content(subframe_rph); + frame_content.OverrideBinderForTesting(subframe); content::ScopedAllowRendererCrashes allow_renderer_crashes(subframe_rph); - subframe_rph->AddFilter(filter.get()); PrintAndWaitUntilPreviewIsReady(/*print_only_selection=*/false); } @@ -762,4 +849,57 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessPrintBrowserTest, MultipagePrint) { PrintAndWaitUntilPreviewIsReadyAndLoaded(/*print_only_selection=*/false); } +IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PDFPluginNotKeyboardFocusable) { + ASSERT_TRUE(embedded_test_server()->Started()); + GURL url(embedded_test_server()->GetURL("/printing/multipage.html")); + ui_test_utils::NavigateToURL(browser(), url); + + PrintPreviewObserver print_preview_observer(/*wait_for_loaded=*/true); + StartPrint(browser()->tab_strip_model()->GetActiveWebContents(), + /*print_renderer=*/mojo::NullAssociatedRemote(), + /*print_preview_disabled=*/false, /*print_only_selection=*/false); + print_preview_observer.WaitUntilPreviewIsReady(); + + content::WebContents* preview_dialog = + print_preview_observer.GetPrintPreviewDialog(); + ASSERT_TRUE(preview_dialog); + + // The script will ensure we return the id of <zoom-out-button> when + // focused. Focus the element after PDF plugin in tab order. + const char kScript[] = R"( + const button = document.getElementsByTagName('print-preview-app')[0] + .$['previewArea'] + .$$('iframe') + .contentDocument.querySelector('pdf-viewer-pp') + .shadowRoot.querySelector('#zoom-toolbar') + .$['zoom-out-button']; + button.addEventListener('focus', (e) => { + window.domAutomationController.send(e.target.id); + }); + + const select_tag = document.getElementsByTagName('print-preview-app')[0] + .$['sidebar'] + .$['destinationSettings'] + .$['destinationSelect'] + .$$('select'); + select_tag.addEventListener('focus', () => { + window.domAutomationController.send(true); + }); + select_tag.focus();)"; + bool success = false; + ASSERT_TRUE( + content::ExecuteScriptAndExtractBool(preview_dialog, kScript, &success)); + ASSERT_TRUE(success); + + // Simulate a <shift-tab> press and wait for a focus message. + content::DOMMessageQueue msg_queue; + SimulateKeyPress(preview_dialog, ui::DomKey::TAB, ui::DomCode::TAB, + ui::VKEY_TAB, false, true, false, false); + std::string reply; + ASSERT_TRUE(msg_queue.WaitForMessage(&reply)); + // Pressing <shift-tab> should focus the last toolbar element + // (zoom-out-button) instead of PDF plugin. + EXPECT_EQ("\"zoom-out-button\"", reply); +} + } // namespace printing |