Commit 13ec987c authored by Alan Screen's avatar Alan Screen Committed by Commit Bot

Add Windows support for printed document metafile

The legacy Windows printing with GDI/EMF has a different print path
from other desktop platforms, as it spools each page of a document
separately so that the results can go through an extra conversion step
from PDF to EMF before being sent to a device.

With XPS printing path no extra conversion step is required, enabling
Windows to use a similar interface as for other desktop platforms and
get the document metafile and simply spool the job.  This CL enables
that option for XPS to coexist with GDI depending upon the
|kUseXpsForPrinting| feature flag.

This CL uses a NOTIMPLEMENTED in PrintingContextWin::PrintDocument()
as a placeholder for where Skia calls will occur, which is to come in
later CL.

Bug: 1008222
Change-Id: I7d6b0a1ef737eaba358f99ed04e047d24a0e895e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1935946Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Commit-Queue: Alan Screen <awscreen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#723446}
parent 3da3033b
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "printing/common/printing_features.h"
#include "printing/printed_page_win.h" #include "printing/printed_page_win.h"
#endif #endif
...@@ -350,13 +351,37 @@ void PrintJobWorker::OnNewPage() { ...@@ -350,13 +351,37 @@ void PrintJobWorker::OnNewPage() {
if (!document_) if (!document_)
return; return;
bool do_spool_job = true;
#if defined(OS_WIN) #if defined(OS_WIN)
if (!base::FeatureList::IsEnabled(printing::features::kUseXpsForPrinting)) {
// Using the Windows GDI print API.
if (!OnNewPageHelperGdi())
return;
do_spool_job = false;
}
#endif // defined(OS_WIN)
if (do_spool_job) {
if (!document_->GetMetafile()) {
PostWaitForPage();
return;
}
SpoolJob();
}
OnDocumentDone();
// Don't touch |this| anymore since the instance could be destroyed.
}
#if defined(OS_WIN)
bool PrintJobWorker::OnNewPageHelperGdi() {
if (page_number_ == PageNumber::npos()) { if (page_number_ == PageNumber::npos()) {
// Find first page to print. // Find first page to print.
int page_count = document_->page_count(); int page_count = document_->page_count();
if (!page_count) { if (!page_count) {
// We still don't know how many pages the document contains. // We still don't know how many pages the document contains.
return; return false;
} }
// We have enough information to initialize |page_number_|. // We have enough information to initialize |page_number_|.
page_number_.Init(document_->settings(), page_count); page_number_.Init(document_->settings(), page_count);
...@@ -366,7 +391,7 @@ void PrintJobWorker::OnNewPage() { ...@@ -366,7 +391,7 @@ void PrintJobWorker::OnNewPage() {
scoped_refptr<PrintedPage> page = document_->GetPage(page_number_.ToInt()); scoped_refptr<PrintedPage> page = document_->GetPage(page_number_.ToInt());
if (!page) { if (!page) {
PostWaitForPage(); PostWaitForPage();
return; return false;
} }
// The page is there, print it. // The page is there, print it.
SpoolPage(page.get()); SpoolPage(page.get());
...@@ -374,17 +399,9 @@ void PrintJobWorker::OnNewPage() { ...@@ -374,17 +399,9 @@ void PrintJobWorker::OnNewPage() {
if (page_number_ == PageNumber::npos()) if (page_number_ == PageNumber::npos())
break; break;
} }
#else return true;
if (!document_->GetMetafile()) {
PostWaitForPage();
return;
}
SpoolJob();
#endif // defined(OS_WIN)
OnDocumentDone();
// Don't touch |this| anymore since the instance could be destroyed.
} }
#endif // defined(OS_WIN)
void PrintJobWorker::Cancel() { void PrintJobWorker::Cancel() {
// This is the only function that can be called from any thread. // This is the only function that can be called from any thread.
...@@ -467,13 +484,13 @@ void PrintJobWorker::SpoolPage(PrintedPage* page) { ...@@ -467,13 +484,13 @@ void PrintJobWorker::SpoolPage(PrintedPage* page) {
JobEventDetails::PAGE_DONE, printing_context_->job_id(), JobEventDetails::PAGE_DONE, printing_context_->job_id(),
base::RetainedRef(document_), base::RetainedRef(page))); base::RetainedRef(document_), base::RetainedRef(page)));
} }
#else #endif // defined(OS_WIN)
void PrintJobWorker::SpoolJob() { void PrintJobWorker::SpoolJob() {
DCHECK(task_runner_->RunsTasksInCurrentSequence()); DCHECK(task_runner_->RunsTasksInCurrentSequence());
if (!document_->RenderPrintedDocument(printing_context_.get())) if (!document_->RenderPrintedDocument(printing_context_.get()))
OnFailure(); OnFailure();
} }
#endif
void PrintJobWorker::OnFailure() { void PrintJobWorker::OnFailure() {
DCHECK(task_runner_->RunsTasksInCurrentSequence()); DCHECK(task_runner_->RunsTasksInCurrentSequence());
......
...@@ -114,12 +114,16 @@ class PrintJobWorker { ...@@ -114,12 +114,16 @@ class PrintJobWorker {
void PostWaitForPage(); void PostWaitForPage();
#if defined(OS_WIN) #if defined(OS_WIN)
// Windows print GDI-specific handling for OnNewPage().
bool OnNewPageHelperGdi();
// Renders a page in the printer. // Renders a page in the printer.
// This is applicable when using the Windows GDI print API.
void SpoolPage(PrintedPage* page); void SpoolPage(PrintedPage* page);
#else #endif // defined(OS_WIN)
// Renders the document to the printer. // Renders the document to the printer.
void SpoolJob(); void SpoolJob();
#endif
// Closes the job since spooling is done. // Closes the job since spooling is done.
void OnDocumentDone(); void OnDocumentDone();
......
...@@ -58,7 +58,8 @@ void DebugDumpPageTask(const base::string16& doc_name, ...@@ -58,7 +58,8 @@ void DebugDumpPageTask(const base::string16& doc_name,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
page->metafile()->SaveTo(&file); page->metafile()->SaveTo(&file);
} }
#else #endif // defined(OS_WIN)
void DebugDumpTask(const base::string16& doc_name, void DebugDumpTask(const base::string16& doc_name,
const MetafilePlayer* metafile) { const MetafilePlayer* metafile) {
DCHECK(PrintedDocument::HasDebugDumpPath()); DCHECK(PrintedDocument::HasDebugDumpPath());
...@@ -72,7 +73,6 @@ void DebugDumpTask(const base::string16& doc_name, ...@@ -72,7 +73,6 @@ void DebugDumpTask(const base::string16& doc_name,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
metafile->SaveTo(&file); metafile->SaveTo(&file);
} }
#endif
void DebugDumpDataTask(const base::string16& doc_name, void DebugDumpDataTask(const base::string16& doc_name,
const base::FilePath::StringType& extension, const base::FilePath::StringType& extension,
...@@ -156,8 +156,8 @@ scoped_refptr<PrintedPage> PrintedDocument::GetPage(int page_number) { ...@@ -156,8 +156,8 @@ scoped_refptr<PrintedPage> PrintedDocument::GetPage(int page_number) {
} }
return page; return page;
} }
#endif // defined(OS_WIN)
#else
void PrintedDocument::SetDocument(std::unique_ptr<MetafilePlayer> metafile, void PrintedDocument::SetDocument(std::unique_ptr<MetafilePlayer> metafile,
const gfx::Size& page_size, const gfx::Size& page_size,
const gfx::Rect& page_content_rect) { const gfx::Rect& page_content_rect) {
...@@ -182,8 +182,6 @@ const MetafilePlayer* PrintedDocument::GetMetafile() { ...@@ -182,8 +182,6 @@ const MetafilePlayer* PrintedDocument::GetMetafile() {
return mutable_.metafile_.get(); return mutable_.metafile_.get();
} }
#endif
bool PrintedDocument::IsComplete() const { bool PrintedDocument::IsComplete() const {
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
if (!mutable_.page_count_) if (!mutable_.page_count_)
......
...@@ -46,6 +46,7 @@ class PRINTING_EXPORT PrintedDocument ...@@ -46,6 +46,7 @@ class PRINTING_EXPORT PrintedDocument
// Indicates that the PDF has been generated and the document is waiting for // Indicates that the PDF has been generated and the document is waiting for
// conversion for printing. This is needed on Windows so that the print job // conversion for printing. This is needed on Windows so that the print job
// is not cancelled if the web contents dies before PDF conversion finishes. // is not cancelled if the web contents dies before PDF conversion finishes.
// This is applicable when using the GDI print API.
void SetConvertingPdf(); void SetConvertingPdf();
// Sets a page's data. 0-based. Note: locks for a short amount of time. // Sets a page's data. 0-based. Note: locks for a short amount of time.
...@@ -59,7 +60,8 @@ class PRINTING_EXPORT PrintedDocument ...@@ -59,7 +60,8 @@ class PRINTING_EXPORT PrintedDocument
// requests to have this page be rendered and returns NULL. // requests to have this page be rendered and returns NULL.
// Note: locks for a short amount of time. // Note: locks for a short amount of time.
scoped_refptr<PrintedPage> GetPage(int page_number); scoped_refptr<PrintedPage> GetPage(int page_number);
#else #endif // defined(OS_WIN)
// Sets the document data. Note: locks for a short amount of time. // Sets the document data. Note: locks for a short amount of time.
void SetDocument(std::unique_ptr<MetafilePlayer> metafile, void SetDocument(std::unique_ptr<MetafilePlayer> metafile,
const gfx::Size& page_size, const gfx::Size& page_size,
...@@ -68,18 +70,18 @@ class PRINTING_EXPORT PrintedDocument ...@@ -68,18 +70,18 @@ class PRINTING_EXPORT PrintedDocument
// Retrieves the metafile with the data to print. Lock must be held when // Retrieves the metafile with the data to print. Lock must be held when
// calling this function // calling this function
const MetafilePlayer* GetMetafile(); const MetafilePlayer* GetMetafile();
#endif
// Draws the page in the context. // Draws the page in the context.
// Note: locks for a short amount of time in debug only. // Note: locks for a short amount of time in debug only.
#if defined(OS_WIN) #if defined(OS_WIN)
// This is applicable when using the Windows GDI print API.
void RenderPrintedPage(const PrintedPage& page, void RenderPrintedPage(const PrintedPage& page,
printing::NativeDrawingContext context) const; printing::NativeDrawingContext context) const;
#elif defined(OS_POSIX) #endif
// Draws the document in the context. Returns true on success and false on // Draws the document in the context. Returns true on success and false on
// failure. Fails if context->NewPage() or context->PageDone() fails. // failure. Fails if context->NewPage() or context->PageDone() fails.
bool RenderPrintedDocument(PrintingContext* context); bool RenderPrintedDocument(PrintingContext* context);
#endif
// Returns true if all the necessary pages for the settings are already // Returns true if all the necessary pages for the settings are already
// rendered. // rendered.
...@@ -154,16 +156,20 @@ class PRINTING_EXPORT PrintedDocument ...@@ -154,16 +156,20 @@ class PRINTING_EXPORT PrintedDocument
// The total number of pages in the document. // The total number of pages in the document.
int page_count_ = 0; int page_count_ = 0;
std::unique_ptr<MetafilePlayer> metafile_;
#if defined(OS_WIN) #if defined(OS_WIN)
// Contains the pages' representation. This is a collection of PrintedPage. // Contains the pages' representation. This is a collection of PrintedPage.
// Warning: Lock must be held when accessing this member. // Warning: Lock must be held when accessing this member.
// This is applicable when using the Windows GDI print API which has the
// extra conversion step from PDF to EMF prior to sending to device.
// The metafile_ field is not used in this scenario.
PrintedPages pages_; PrintedPages pages_;
// Whether the PDF is being converted for printing. // Whether the PDF is being converted for printing.
bool converting_pdf_ = false; bool converting_pdf_ = false;
#else
std::unique_ptr<MetafilePlayer> metafile_;
#endif #endif
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
gfx::Size page_size_; gfx::Size page_size_;
gfx::Rect page_content_rect_; gfx::Rect page_content_rect_;
......
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
#include "printing/printed_document.h" #include "printing/printed_document.h"
#include "base/logging.h" #include "base/logging.h"
#include "printing/metafile_skia.h"
#include "printing/page_number.h" #include "printing/page_number.h"
#include "printing/printed_page_win.h" #include "printing/printed_page_win.h"
#include "printing/printing_context_win.h"
#include "printing/units.h" #include "printing/units.h"
#include "skia/ext/skia_utils_win.h" #include "skia/ext/skia_utils_win.h"
...@@ -77,4 +79,18 @@ void PrintedDocument::RenderPrintedPage( ...@@ -77,4 +79,18 @@ void PrintedDocument::RenderPrintedPage(
DCHECK_NE(res, 0); DCHECK_NE(res, 0);
} }
bool PrintedDocument::RenderPrintedDocument(PrintingContext* context) {
if (context->NewPage() != PrintingContext::OK)
return false;
base::string16 device_name = immutable_.settings_->device_name();
{
base::AutoLock lock(lock_);
const MetafilePlayer* metafile = GetMetafile();
static_cast<PrintingContextWin*>(context)->PrintDocument(
device_name, *(static_cast<const MetafileSkia*>(metafile)));
}
return context->PageDone() == PrintingContext::OK;
}
} // namespace printing } // namespace printing
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include "printing/backend/print_backend.h" #include "printing/backend/print_backend.h"
#include "printing/backend/win_helper.h" #include "printing/backend/win_helper.h"
#include "printing/buildflags/buildflags.h" #include "printing/buildflags/buildflags.h"
#include "printing/common/printing_features.h"
#include "printing/metafile_skia.h"
#include "printing/print_settings_initializer_win.h" #include "printing/print_settings_initializer_win.h"
#include "printing/printed_document.h" #include "printing/printed_document.h"
#include "printing/printing_context_system_dialog_win.h" #include "printing/printing_context_system_dialog_win.h"
...@@ -58,6 +60,12 @@ PrintingContextWin::~PrintingContextWin() { ...@@ -58,6 +60,12 @@ PrintingContextWin::~PrintingContextWin() {
ReleaseContext(); ReleaseContext();
} }
void PrintingContextWin::PrintDocument(const base::string16& device_name,
const MetafileSkia& metafile) {
// TODO(crbug.com/1008222)
NOTIMPLEMENTED();
}
void PrintingContextWin::AskUserForSettings(int max_pages, void PrintingContextWin::AskUserForSettings(int max_pages,
bool has_selection, bool has_selection,
bool is_scripted, bool is_scripted,
...@@ -260,6 +268,11 @@ PrintingContext::Result PrintingContextWin::NewDocument( ...@@ -260,6 +268,11 @@ PrintingContext::Result PrintingContextWin::NewDocument(
in_print_job_ = true; in_print_job_ = true;
if (base::FeatureList::IsEnabled(printing::features::kUseXpsForPrinting))
return OK; // This is all the new document context needed when using XPS.
// Need more context setup when using GDI.
// Register the application's AbortProc function with GDI. // Register the application's AbortProc function with GDI.
if (SP_ERROR == SetAbortProc(context_, &AbortProc)) if (SP_ERROR == SetAbortProc(context_, &AbortProc))
return OnError(); return OnError();
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
namespace printing { namespace printing {
class MetafileSkia;
class PrintSettings; class PrintSettings;
class PRINTING_EXPORT PrintingContextWin : public PrintingContext { class PRINTING_EXPORT PrintingContextWin : public PrintingContext {
...@@ -21,6 +22,10 @@ class PRINTING_EXPORT PrintingContextWin : public PrintingContext { ...@@ -21,6 +22,10 @@ class PRINTING_EXPORT PrintingContextWin : public PrintingContext {
explicit PrintingContextWin(Delegate* delegate); explicit PrintingContextWin(Delegate* delegate);
~PrintingContextWin() override; ~PrintingContextWin() override;
// Prints the document contained in |metafile|.
void PrintDocument(const base::string16& device_name,
const MetafileSkia& metafile);
// Initializes with predefined settings. // Initializes with predefined settings.
Result InitWithSettingsForTest(std::unique_ptr<PrintSettings> settings); Result InitWithSettingsForTest(std::unique_ptr<PrintSettings> settings);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment