0

Add service-based usage for printing document done

Incorporate usage of printing document done from within the Print
Backend service utility.  At this point it is only used by Windows.
Use by macOS, Linux, and ChromeOS is forthcoming when rendering for
printed document support is filled in.

Bug: 809738
Change-Id: Icb1556b144138c5c98cd0abe9964cb3d0ddf4458
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3199044
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Alan Screen <awscreen@chromium.org>
Cr-Commit-Position: refs/heads/main@{#968690}
This commit is contained in:
Alan Screen
2022-02-09 01:33:43 +00:00
committed by Chromium LUCI CQ
parent 96aa08c3c8
commit 56bb8eae5f
7 changed files with 151 additions and 22 deletions

@ -95,6 +95,8 @@ using OnDidRenderPrintedPageCallback =
base::RepeatingCallback<void(uint32_t page_number,
mojom::ResultCode result)>;
#endif
using OnDidDocumentDoneCallback =
base::RepeatingCallback<void(mojom::ResultCode result)>;
using OnDidShowErrorDialog = base::RepeatingCallback<void()>;
using OnStopCallback = base::RepeatingCallback<void()>;
@ -115,6 +117,7 @@ struct TestPrintCallbacks {
#if BUILDFLAG(IS_WIN)
OnDidRenderPrintedPageCallback did_render_printed_page_callback;
#endif
OnDidDocumentDoneCallback did_document_done_callback;
// The exceptions to the callback steps are `did_show_error_dialog` and
// `did_stop_callback`. For `did_stop_callback` there is no result code
@ -1885,6 +1888,13 @@ class TestPrintJobWorker : public PrintJobWorkerOop {
}
#endif // BUILDFLAG(IS_WIN)
void OnDidDocumentDone(int job_id, mojom::ResultCode result) override {
DVLOG(1) << "Observed: document done";
callbacks_->error_check_callback.Run(result);
PrintJobWorkerOop::OnDidDocumentDone(job_id, result);
callbacks_->did_document_done_callback.Run(result);
}
void ShowErrorDialog() override {
// Do not show real error dialog, it blocks the UI thread.
DVLOG(1) << "Test: notify user of print error";
@ -1930,6 +1940,9 @@ class PrintBackendPrintBrowserTestBase : public PrintBrowserTest {
&PrintBackendPrintBrowserTestBase::OnDidRenderPrintedPage,
base::Unretained(this));
#endif
test_print_callbacks_.did_document_done_callback = base::BindRepeating(
&PrintBackendPrintBrowserTestBase::OnDidDocumentDone,
base::Unretained(this));
test_print_callbacks_.did_show_error_dialog = base::BindRepeating(
&PrintBackendPrintBrowserTestBase::OnDidShowErrorDialog,
base::Unretained(this));
@ -2039,6 +2052,11 @@ class PrintBackendPrintBrowserTestBase : public PrintBrowserTest {
}
#endif
void PrimeForAccessDeniedErrorsInDocumentDone() {
test_printing_context_factory_.SetAccessDeniedErrorOnDocumentDone(
/*cause_errors=*/true);
}
mojom::ResultCode start_printing_result() const {
return start_printing_result_;
}
@ -2050,6 +2068,10 @@ class PrintBackendPrintBrowserTestBase : public PrintBrowserTest {
int render_printed_page_count() const { return render_printed_pages_count_; }
#endif // BUILDFLAG(IS_WIN)
mojom::ResultCode document_done_result() const {
return document_done_result_;
}
bool error_dialog_shown() const { return error_dialog_shown_; }
bool stop_invoked() const { return stop_invoked_; }
@ -2077,6 +2099,8 @@ class PrintBackendPrintBrowserTestBase : public PrintBrowserTest {
if (access_denied_errors_for_render_page_)
context->SetOnRenderPageBlockedByPermissions();
#endif
if (access_denied_errors_for_document_done_)
context->SetDocumentDoneBlockedByPermissions();
return std::move(context);
}
@ -2095,12 +2119,17 @@ class PrintBackendPrintBrowserTestBase : public PrintBrowserTest {
}
#endif
void SetAccessDeniedErrorOnDocumentDone(bool cause_errors) {
access_denied_errors_for_document_done_ = cause_errors;
}
private:
std::string printer_name_;
bool access_denied_errors_for_new_document_ = false;
#if BUILDFLAG(IS_WIN)
bool access_denied_errors_for_render_page_ = false;
#endif
bool access_denied_errors_for_document_done_ = false;
};
#if BUILDFLAG(ENABLE_OOP_PRINTING)
@ -2133,6 +2162,11 @@ class PrintBackendPrintBrowserTestBase : public PrintBrowserTest {
}
#endif
void OnDidDocumentDone(mojom::ResultCode result) {
document_done_result_ = result;
CheckForQuit();
}
void OnDidShowErrorDialog() {
error_dialog_shown_ = true;
CheckForQuit();
@ -2154,6 +2188,8 @@ class PrintBackendPrintBrowserTestBase : public PrintBrowserTest {
test_printing_context_factory_.SetAccessDeniedErrorOnRenderPage(
/*cause_errors=*/false);
#endif
test_printing_context_factory_.SetAccessDeniedErrorOnDocumentDone(
/*cause_errors=*/false);
}
base::test::ScopedFeatureList feature_list_;
@ -2173,6 +2209,7 @@ class PrintBackendPrintBrowserTestBase : public PrintBrowserTest {
mojom::ResultCode render_printed_page_result_ = mojom::ResultCode::kFailed;
int render_printed_pages_count_ = 0;
#endif
mojom::ResultCode document_done_result_ = mojom::ResultCode::kFailed;
bool error_dialog_shown_ = false;
bool stop_invoked_ = false;
};
@ -2259,10 +2296,11 @@ IN_PROC_BROWSER_TEST_F(PrintBackendPrintBrowserTestService, StartPrinting) {
SetUpPrintViewManager(web_contents);
#if BUILDFLAG(IS_WIN)
// The test will succeed to start the print job and render a page of content.
// Wait for a call to `Stop()` to ensure print job wrap-up finished cleanly
// before completing the test. This results in a total of 3 expected calls.
SetNumExpectedMessages(/*num=*/3);
// The test will succeed to start the print job, render a page of content,
// and complete with document done. Wait for a call to `Stop()` to ensure
// print job wrap-up finished cleanly before completing the test. This
// results in a total of 4 expected calls.
SetNumExpectedMessages(/*num=*/4);
#else
// The test will succeed to start printing. Wait for a call to `Stop()` to
// ensure print job wrap-up finished cleanly before completing the test.
@ -2275,6 +2313,7 @@ IN_PROC_BROWSER_TEST_F(PrintBackendPrintBrowserTestService, StartPrinting) {
#if BUILDFLAG(IS_WIN)
EXPECT_EQ(render_printed_page_result(), mojom::ResultCode::kSuccess);
EXPECT_EQ(render_printed_page_count(), 1);
EXPECT_EQ(document_done_result(), mojom::ResultCode::kSuccess);
#endif
EXPECT_TRUE(stop_invoked());
}
@ -2296,11 +2335,10 @@ IN_PROC_BROWSER_TEST_F(PrintBackendPrintBrowserTestService,
#if BUILDFLAG(IS_WIN)
// The test will retry to print after getting an access-denied error when
// trying to start printing. After that the printing will succeed to start
// and render a page of content. Wait for a call to `Stop()` to ensure print
// job wrap-up finished cleanly before completing the test. This results in
// a total of 4 expected calls.
SetNumExpectedMessages(/*num=*/4);
// trying to start printing. After that the printing will succeed to start,
// render a page of content, and complete. Wait for a call to `Stop()` to
// ensure print job wrap-up finished cleanly - resulting in 5 calls.
SetNumExpectedMessages(/*num=*/5);
#else
// The test will retry to print after getting an access-denied error when
// trying to start printing. After that the printing will succeed to start.
@ -2314,6 +2352,7 @@ IN_PROC_BROWSER_TEST_F(PrintBackendPrintBrowserTestService,
#if BUILDFLAG(IS_WIN)
EXPECT_EQ(render_printed_page_result(), mojom::ResultCode::kSuccess);
EXPECT_EQ(render_printed_page_count(), 1);
EXPECT_EQ(document_done_result(), mojom::ResultCode::kSuccess);
#endif
EXPECT_TRUE(stop_invoked());
}
@ -2382,6 +2421,43 @@ IN_PROC_BROWSER_TEST_F(PrintBackendPrintBrowserTestService,
}
#endif // BUILDFLAG(IS_WIN)
// TODO(crbug.com/809738) Enable for other platforms once support is added
// for `RenderPrintedDocument()`.
#if BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(PrintBackendPrintBrowserTestService,
StartPrintingDocumentDoneAccessDenied) {
AddPrinter("printer1");
SetPrinterNameForSubsequentContexts("printer1");
PrimeForAccessDeniedErrorsInDocumentDone();
ASSERT_TRUE(embedded_test_server()->Started());
GURL url(embedded_test_server()->GetURL("/printing/test3.html"));
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents);
SetUpPrintViewManager(web_contents);
// No attempt to retry is made if an access-denied error occurs when trying
// do wrap-up a rendered document. The test will fail after starting the
// print job, rendering a page of content, and calling for document done.
// This will cause a printing error dialog to be displayed. Wait for a call
// to `Stop()` to ensure print job wrap-up finished cleanly before completing
// the test. This results in a total of 5 expected calls.
SetNumExpectedMessages(/*num=*/5);
PrintAfterPreviewIsReadyAndLoaded();
EXPECT_EQ(start_printing_result(), mojom::ResultCode::kSuccess);
EXPECT_EQ(render_printed_page_result(), mojom::ResultCode::kSuccess);
EXPECT_EQ(render_printed_page_count(), 1);
EXPECT_EQ(document_done_result(), mojom::ResultCode::kAccessDenied);
EXPECT_TRUE(error_dialog_shown());
EXPECT_TRUE(stop_invoked());
}
#endif // BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(ENABLE_OOP_PRINTING)
#endif // !BUILDFLAG(IS_CHROMEOS)

@ -486,12 +486,16 @@ bool PrintJobWorker::Start() {
return result;
}
void PrintJobWorker::OnDocumentDone() {
void PrintJobWorker::CheckDocumentSpoolingComplete() {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
DCHECK_EQ(page_number_, PageNumber::npos());
DCHECK(document_);
// PrintJob must own this, because only PrintJob can send notifications.
DCHECK(print_job_);
}
void PrintJobWorker::OnDocumentDone() {
CheckDocumentSpoolingComplete();
int job_id = printing_context_->job_id();
if (printing_context_->DocumentDone() != mojom::ResultCode::kSuccess) {
@ -499,6 +503,10 @@ void PrintJobWorker::OnDocumentDone() {
return;
}
FinishDocumentDone(job_id);
}
void PrintJobWorker::FinishDocumentDone(int job_id) {
print_job_->PostTask(
FROM_HERE, base::BindOnce(&DocDoneNotificationCallback,
base::RetainedRef(print_job_.get()), job_id,

@ -121,9 +121,15 @@ class PrintJobWorker {
virtual void SpoolPage(PrintedPage* page);
#endif
// Internal state verification that spooling of the document is complete.
void CheckDocumentSpoolingComplete();
// Closes the job since spooling is done.
virtual void OnDocumentDone();
// Helper function for document done processing.
void FinishDocumentDone(int job_id);
// Reports settings back to `callback`.
void GetSettingsDone(SettingsCallback callback, mojom::ResultCode result);

@ -4,6 +4,7 @@
#include "chrome/browser/printing/print_job_worker_oop.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
@ -130,13 +131,30 @@ void PrintJobWorkerOop::OnDidRenderPrintedPage(uint32_t page_index,
if (pages_printed_count_ == document()->page_count()) {
// The last page has printed, can proceed to document done processing.
VLOG(1) << "All pages printed for document";
// TODO(crbug.com/809738) Proceed with `DocumentDone()` processing.
task_runner()->PostTask(FROM_HERE,
base::BindOnce(&PrintJobWorkerOop::OnFailure,
worker_weak_factory_.GetWeakPtr()));
SendDocumentDone();
}
}
#endif // BUILDFLAG(IS_WIN)
void PrintJobWorkerOop::OnDidDocumentDone(int job_id,
mojom::ResultCode result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
#if BUILDFLAG(IS_WIN)
DCHECK_EQ(pages_printed_count_, document()->page_count());
#endif
if (result != mojom::ResultCode::kSuccess) {
VLOG(1) << "Error completing printing via service for document "
<< document()->cookie() << ": " << result;
NotifyFailure(result);
return;
}
VLOG(1) << "Printing completed with service for document "
<< document()->cookie();
UnregisterServiceManagerClient();
FinishDocumentDone(job_id);
}
#if BUILDFLAG(IS_WIN)
void PrintJobWorkerOop::SpoolPage(PrintedPage* page) {
DCHECK(task_runner()->RunsTasksInCurrentSequence());
DCHECK_NE(page_number(), PageNumber::npos());
@ -165,16 +183,13 @@ void PrintJobWorkerOop::SpoolPage(PrintedPage* page) {
#endif // BUILDFLAG(IS_WIN)
void PrintJobWorkerOop::OnDocumentDone() {
DCHECK(task_runner()->RunsTasksInCurrentSequence());
// Can do browser-side checks related to completeness for sending, but must
// wait to do OOP related checks until OnDidDocumentDone() is received.
DCHECK_EQ(page_number(), PageNumber::npos());
DCHECK(document());
// PrintJob must own this, because only PrintJob can send notifications.
DCHECK(print_job());
// wait to do OOP related work until OnDidDocumentDone() is received.
CheckDocumentSpoolingComplete();
// TODO(crbug.com/809738) Further OOP logic pending.
// Since this call occurs due to all pages having been sent, do not just call
// `SendDocumentDone()`. That should happen as a result of callbacks from
// PrintBackend service.
}
void PrintJobWorkerOop::UpdatePrintSettings(base::Value new_settings,
@ -342,4 +357,19 @@ void PrintJobWorkerOop::SendRenderPrintedPage(
}
#endif // BUILDFLAG(IS_WIN)
void PrintJobWorkerOop::SendDocumentDone() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const int32_t document_cookie = document()->cookie();
VLOG(1) << "Sending document done for document " << document_cookie;
PrintBackendServiceManager& service_mgr =
PrintBackendServiceManager::GetInstance();
service_mgr.DocumentDone(device_name_, document_cookie,
base::BindOnce(&PrintJobWorkerOop::OnDidDocumentDone,
ui_weak_factory_.GetWeakPtr(),
printing_context()->job_id()));
}
} // namespace printing

@ -47,6 +47,7 @@ class PrintJobWorkerOop : public PrintJobWorker {
virtual void OnDidRenderPrintedPage(uint32_t page_index,
mojom::ResultCode result);
#endif
virtual void OnDidDocumentDone(int job_id, mojom::ResultCode result);
// `PrintJobWorker` overrides.
#if BUILDFLAG(IS_WIN)
@ -85,6 +86,7 @@ class PrintJobWorkerOop : public PrintJobWorker {
mojom::MetafileDataType page_data_type,
base::ReadOnlySharedMemoryRegion serialized_page_data);
#endif // BUILDFLAG(IS_WIN)
void SendDocumentDone();
// Client ID with the print backend service manager for this print job.
// Used only from UI thread.

@ -149,6 +149,9 @@ mojom::ResultCode TestPrintingContext::DocumentDone() {
DCHECK(in_print_job_);
DVLOG(1) << "Document done";
if (document_done_blocked_by_permissions_)
return mojom::ResultCode::kAccessDenied;
ResetSettings();
return mojom::ResultCode::kSuccess;
}

@ -52,6 +52,9 @@ class TestPrintingContext : public PrintingContext {
render_page_blocked_by_permissions_ = true;
}
#endif
void SetDocumentDoneBlockedByPermissions() {
document_done_blocked_by_permissions_ = true;
}
// PrintingContext overrides:
void AskUserForSettings(int max_pages,
@ -85,6 +88,7 @@ class TestPrintingContext : public PrintingContext {
#if BUILDFLAG(IS_WIN)
bool render_page_blocked_by_permissions_ = false;
#endif
bool document_done_blocked_by_permissions_ = false;
};
} // namespace printing