From 19420756538dd841c1a1ee260a001f28e87ea13b Mon Sep 17 00:00:00 2001 From: xlou Date: Thu, 26 Apr 2018 23:42:44 +0000 Subject: [PATCH] Add N-up feature support to pdfium_engine. In printing, 2-up, 3-up, or more generally N-up refers to a page layout strategy in which multiple pages are composited onto a single page. 1. Added ability to pass the N-up feature UI settings(which will be added in the next CL) to the print preview workflow, so that the PDF plugin can take action based on user's input. 2. Added N-up feature support to pdfium_engine, so that when the source is PDF, pdf plugin will generate the N-up output doc based on user's input. These changes have been reviewed in: https://chromium-review.googlesource.com/c/chromium/src/+/1014628. Bug: 775999 Change-Id: I552c9c91e32af0faa6ffaa8c42ac0652f470f791 Reviewed-on: https://chromium-review.googlesource.com/1028992 Reviewed-by: Lei Zhang Reviewed-by: Daniel Cheng Reviewed-by: Jochen Eisinger Commit-Queue: Shirleen Lou Cr-Commit-Position: refs/heads/master@{#554188} --- .../printing/browser/print_manager_utils.cc | 1 + components/printing/common/print_messages.cc | 4 +- components/printing/common/print_messages.h | 6 + .../renderer/print_render_frame_helper.cc | 3 + .../pepper/pepper_print_settings_manager.cc | 1 + .../pepper/pepper_plugin_instance_impl.cc | 3 + pdf/pdfium/DEPS | 1 + pdf/pdfium/pdfium_engine.cc | 106 +++++++++++++++--- pdf/pdfium/pdfium_engine.h | 9 ++ ppapi/api/dev/pp_print_settings_dev.idl | 4 +- ppapi/c/dev/pp_print_settings_dev.h | 4 +- ppapi/proxy/ppapi_messages.h | 1 + printing/print_settings.cc | 1 + printing/print_settings.h | 8 ++ printing/print_settings_conversion.cc | 4 + .../blink/public/web/web_print_params.h | 15 ++- 16 files changed, 150 insertions(+), 21 deletions(-) diff --git a/components/printing/browser/print_manager_utils.cc b/components/printing/browser/print_manager_utils.cc index 59b9ca8642f495..a38d8ab661b17c 100644 --- a/components/printing/browser/print_manager_utils.cc +++ b/components/printing/browser/print_manager_utils.cc @@ -68,6 +68,7 @@ void RenderParamsFromPrintSettings(const PrintSettings& settings, params->url = settings.url(); params->printed_doc_type = IsOopifEnabled() ? SkiaDocumentType::MSKP : SkiaDocumentType::PDF; + params->num_pages_per_sheet = settings.num_pages_per_sheet(); } } // namespace printing diff --git a/components/printing/common/print_messages.cc b/components/printing/common/print_messages.cc index b308dc410ffba2..f4647d65aeda09 100644 --- a/components/printing/common/print_messages.cc +++ b/components/printing/common/print_messages.cc @@ -96,7 +96,8 @@ PrintMsg_Print_Params::PrintMsg_Print_Params() footer_template(), should_print_backgrounds(false), printed_doc_type(printing::SkiaDocumentType::PDF), - prefer_css_page_size(false) {} + prefer_css_page_size(false), + num_pages_per_sheet(1) {} PrintMsg_Print_Params::PrintMsg_Print_Params( const PrintMsg_Print_Params& other) = default; @@ -128,6 +129,7 @@ void PrintMsg_Print_Params::Reset() { should_print_backgrounds = false; printed_doc_type = printing::SkiaDocumentType::PDF; prefer_css_page_size = false; + num_pages_per_sheet = 1; } PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params() diff --git a/components/printing/common/print_messages.h b/components/printing/common/print_messages.h index b9e8aa76fe5a71..cd3fe2986af209 100644 --- a/components/printing/common/print_messages.h +++ b/components/printing/common/print_messages.h @@ -63,6 +63,7 @@ struct PrintMsg_Print_Params { bool should_print_backgrounds; printing::SkiaDocumentType printed_doc_type; bool prefer_css_page_size; + int num_pages_per_sheet; }; struct PrintMsg_PrintPages_Params { @@ -191,6 +192,11 @@ IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params) // True if page size defined by css should be preferred. IPC_STRUCT_TRAITS_MEMBER(prefer_css_page_size) + + // Number of pages per sheet. This parameter is for N-up mode. + // Defaults to 1 if the feature is disabled, and some number greater + // than 1 otherwise. See printing::NupParameters for supported values. + IPC_STRUCT_TRAITS_MEMBER(num_pages_per_sheet) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(printing::PageRange) diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc index d73427c00ea909..633afea83efad1 100644 --- a/components/printing/renderer/print_render_frame_helper.cc +++ b/components/printing/renderer/print_render_frame_helper.cc @@ -310,6 +310,9 @@ void ComputeWebKitPrintParamsInDesiredDpi( ConvertUnit(print_params.page_size.width(), dpi, kPointsPerInch); webkit_print_params->paper_size.height = ConvertUnit(print_params.page_size.height(), dpi, kPointsPerInch); + + // The following settings is for N-up mode. + webkit_print_params->num_pages_per_sheet = print_params.num_pages_per_sheet; } blink::WebPlugin* GetPlugin(const blink::WebLocalFrame* frame) { diff --git a/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc b/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc index 0a3c9da3d24c87..21dd936082b970 100644 --- a/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc +++ b/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc @@ -86,6 +86,7 @@ PepperPrintSettingsManager::Result ComputeDefaultPrintSettings() { settings.paper_size = PrintSizeToPPPrintSize(page_setup.physical_size(), device_units_per_inch); settings.dpi = print_settings.dpi(); + settings.num_pages_per_sheet = print_settings.num_pages_per_sheet(); // The remainder of the attributes are hard-coded to the defaults as set // elsewhere. diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 0cee2cfe6a09ac..67cc02c76ecf35 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc @@ -1974,6 +1974,9 @@ int PepperPluginInstanceImpl::PrintBegin(const WebPrintParams& print_params) { print_settings.print_scaling_option = static_cast(print_params.print_scaling_option); print_settings.format = format; + + print_settings.num_pages_per_sheet = print_params.num_pages_per_sheet; + num_pages = plugin_print_interface_->Begin(pp_instance(), &print_settings); if (!num_pages) return 0; diff --git a/pdf/pdfium/DEPS b/pdf/pdfium/DEPS index 00a544d46937c7..5e8aa4cb995655 100644 --- a/pdf/pdfium/DEPS +++ b/pdf/pdfium/DEPS @@ -1,6 +1,7 @@ include_rules = [ "+gin/array_buffer.h", "+gin/public", + "+printing/nup_parameters.h", "+third_party/pdfium/public", "+ui/gfx/codec/jpeg_codec.h", ] diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index 1d0303c374315c..6a25cd013d119d 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc @@ -50,6 +50,7 @@ #include "ppapi/cpp/url_response_info.h" #include "ppapi/cpp/var.h" #include "ppapi/cpp/var_dictionary.h" +#include "printing/nup_parameters.h" #include "printing/units.h" #include "third_party/pdfium/public/cpp/fpdf_scopers.h" #include "third_party/pdfium/public/fpdf_annot.h" @@ -709,6 +710,30 @@ std::string ConvertViewIntToViewString(unsigned long view_int) { } } +// UI should have done parameter sanity check, when execution +// reaches here, |num_pages_per_sheet| should be a positive integer. +bool ShouldDoNup(int num_pages_per_sheet) { + return num_pages_per_sheet > 1; +} + +// Check the source doc orientation. Returns true if the doc is landscape. +// For now the orientation of the doc is determined by its first page's +// orientation. Improvement can be added in the future to better determine the +// orientation of the source docs that have mixed orientation. +// TODO(xlou): rotate pages if the source doc has mixed orientation. So that +// the orientation of all pages of the doc are uniform. Pages of square size +// will not be rotated. +bool IsSourcePdfLandscape(FPDF_DOCUMENT doc) { + DCHECK(doc); + + ScopedFPDFPage pdf_page(FPDF_LoadPage(doc, 0)); + DCHECK(pdf_page); + + bool is_source_landscape = + FPDF_GetPageWidth(pdf_page.get()) > FPDF_GetPageHeight(pdf_page.get()); + return is_source_landscape; +} + } // namespace bool InitializeSDK() { @@ -1707,16 +1732,21 @@ pp::Buffer_Dev PDFiumEngine::PrintPagesAsRasterPDF( pp::Buffer_Dev buffer; if (i == pages_to_print.size()) { FPDF_CopyViewerPreferences(output_doc, doc_); - FitContentsToPrintableAreaIfRequired(output_doc, print_settings); - // Now flatten all the output pages. - buffer = GetFlattenedPrintData(output_doc); + if (ShouldDoNup(print_settings.num_pages_per_sheet)) { + buffer = NupPdfToPdf(output_doc, print_settings); + } else { + FitContentsToPrintableAreaIfRequired(output_doc, print_settings); + buffer = GetPrintData(output_doc); + } } + FPDF_CloseDocument(output_doc); return buffer; } -pp::Buffer_Dev PDFiumEngine::GetFlattenedPrintData(FPDF_DOCUMENT doc) { - pp::Buffer_Dev buffer; +bool PDFiumEngine::FlattenPrintData(FPDF_DOCUMENT doc) { + DCHECK(doc); + ScopedSubstFont scoped_subst_font(this); int page_count = FPDF_GetPageCount(doc); for (int i = 0; i < page_count; ++i) { @@ -1725,9 +1755,15 @@ pp::Buffer_Dev PDFiumEngine::GetFlattenedPrintData(FPDF_DOCUMENT doc) { int flatten_ret = FPDFPage_Flatten(page, FLAT_PRINT); FPDF_ClosePage(page); if (flatten_ret == FLATTEN_FAIL) - return buffer; + return false; } + return true; +} + +pp::Buffer_Dev PDFiumEngine::GetPrintData(FPDF_DOCUMENT doc) { + DCHECK(doc); + pp::Buffer_Dev buffer; PDFiumMemBufferFileWrite output_file_write; if (FPDF_SaveAsCopy(doc, &output_file_write, 0)) { size_t size = output_file_write.size(); @@ -1738,6 +1774,41 @@ pp::Buffer_Dev PDFiumEngine::GetFlattenedPrintData(FPDF_DOCUMENT doc) { return buffer; } +pp::Buffer_Dev PDFiumEngine::GetFlattenedPrintData(FPDF_DOCUMENT doc) { + DCHECK(doc); + + pp::Buffer_Dev buffer; + if (FlattenPrintData(doc)) + buffer = GetPrintData(doc); + return buffer; +} + +pp::Buffer_Dev PDFiumEngine::NupPdfToPdf( + FPDF_DOCUMENT doc, + const PP_PrintSettings_Dev& print_settings) { + DCHECK(doc); + + PP_Size page_size = print_settings.paper_size; + + printing::NupParameters nup_params; + bool is_landscape = IsSourcePdfLandscape(doc); + nup_params.SetParameters(print_settings.num_pages_per_sheet, is_landscape); + + // Import n pages to one. + bool paper_is_landscape = page_size.width > page_size.height; + if (nup_params.landscape() != paper_is_landscape) + std::swap(page_size.width, page_size.height); + + ScopedFPDFDocument output_doc_nup(FPDF_ImportNPagesToOne( + doc, page_size.width, page_size.height, nup_params.num_pages_on_x_axis(), + nup_params.num_pages_on_y_axis())); + if (!output_doc_nup) + return pp::Buffer_Dev(); + + FitContentsToPrintableAreaIfRequired(output_doc_nup.get(), print_settings); + return GetPrintData(output_doc_nup.get()); +} + pp::Buffer_Dev PDFiumEngine::PrintPagesAsPDF( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, @@ -1746,7 +1817,7 @@ pp::Buffer_Dev PDFiumEngine::PrintPagesAsPDF( return pp::Buffer_Dev(); DCHECK(doc_); - FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); + ScopedFPDFDocument output_doc(FPDF_CreateNewDocument()); if (!output_doc) return pp::Buffer_Dev(); @@ -1772,17 +1843,24 @@ pp::Buffer_Dev PDFiumEngine::PrintPagesAsPDF( pages_[page_number]->Unload(); } - FPDF_CopyViewerPreferences(output_doc, doc_); - if (!FPDF_ImportPages(output_doc, doc_, page_number_str.c_str(), 0)) { - FPDF_CloseDocument(output_doc); + FPDF_CopyViewerPreferences(output_doc.get(), doc_); + if (!FPDF_ImportPages(output_doc.get(), doc_, page_number_str.c_str(), 0)) { return pp::Buffer_Dev(); } - FitContentsToPrintableAreaIfRequired(output_doc, print_settings); - // Now flatten all the output pages. - pp::Buffer_Dev buffer = GetFlattenedPrintData(output_doc); - FPDF_CloseDocument(output_doc); + if (!FlattenPrintData(output_doc.get())) { + return pp::Buffer_Dev(); + } + + pp::Buffer_Dev buffer; + if (ShouldDoNup(print_settings.num_pages_per_sheet)) { + buffer = NupPdfToPdf(output_doc.get(), print_settings); + } else { + FitContentsToPrintableAreaIfRequired(output_doc.get(), print_settings); + buffer = GetPrintData(output_doc.get()); + } + return buffer; } diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h index b5be0c1033a634..63596eb476b6bf 100644 --- a/pdf/pdfium/pdfium_engine.h +++ b/pdf/pdfium/pdfium_engine.h @@ -331,7 +331,16 @@ class PDFiumEngine : public PDFEngine, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings); + bool FlattenPrintData(FPDF_DOCUMENT doc); + pp::Buffer_Dev GetPrintData(FPDF_DOCUMENT doc); pp::Buffer_Dev GetFlattenedPrintData(FPDF_DOCUMENT doc); + + // Perform N-up PDF generation from |doc| based on the parameters in + // |print_settings|. On success, the returned buffer contains the N-up version + // of |doc|. On failure, the returned buffer is empty. + pp::Buffer_Dev NupPdfToPdf(FPDF_DOCUMENT doc, + const PP_PrintSettings_Dev& print_settings); + void FitContentsToPrintableAreaIfRequired( FPDF_DOCUMENT doc, const PP_PrintSettings_Dev& print_settings); diff --git a/ppapi/api/dev/pp_print_settings_dev.idl b/ppapi/api/dev/pp_print_settings_dev.idl index 010d1b8cc3a691..cf349fd266fdbb 100644 --- a/ppapi/api/dev/pp_print_settings_dev.idl +++ b/ppapi/api/dev/pp_print_settings_dev.idl @@ -32,7 +32,7 @@ enum PP_PrintScalingOption_Dev { PP_PRINTSCALINGOPTION_LAST = PP_PRINTSCALINGOPTION_SOURCE_SIZE }; -[assert_size(60)] +[assert_size(64)] struct PP_PrintSettings_Dev { /** This is the size of the printable area in points (1/72 of an inch). */ PP_Rect printable_area; @@ -44,4 +44,6 @@ struct PP_PrintSettings_Dev { PP_Bool grayscale; /** Note that Chrome currently only supports PDF printing. */ PP_PrintOutputFormat_Dev format; + /** Note the following parameter is for N-up mode. */ + uint32_t num_pages_per_sheet; }; diff --git a/ppapi/c/dev/pp_print_settings_dev.h b/ppapi/c/dev/pp_print_settings_dev.h index 67c37b20b5091a..29e7908029b1df 100644 --- a/ppapi/c/dev/pp_print_settings_dev.h +++ b/ppapi/c/dev/pp_print_settings_dev.h @@ -68,8 +68,10 @@ struct PP_PrintSettings_Dev { PP_Bool grayscale; /** Note that Chrome currently only supports PDF printing. */ PP_PrintOutputFormat_Dev format; + /** Note the following parameter is for N-up mode. */ + uint32_t num_pages_per_sheet; }; -PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(PP_PrintSettings_Dev, 60); +PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(PP_PrintSettings_Dev, 64); /** * @} */ diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index ff05c1abeb6877..c56d3885f666f3 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -220,6 +220,7 @@ IPC_STRUCT_TRAITS_BEGIN(PP_PrintSettings_Dev) IPC_STRUCT_TRAITS_MEMBER(print_scaling_option) IPC_STRUCT_TRAITS_MEMBER(grayscale) IPC_STRUCT_TRAITS_MEMBER(format) + IPC_STRUCT_TRAITS_MEMBER(num_pages_per_sheet) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(PP_PdfPrintPresetOptions_Dev) diff --git a/printing/print_settings.cc b/printing/print_settings.cc index b95ba27119727e..ae8ad92658a365 100644 --- a/printing/print_settings.cc +++ b/printing/print_settings.cc @@ -181,6 +181,7 @@ void PrintSettings::Clear() { printer_type_ = PrintSettings::PrinterType::TYPE_NONE; #endif is_modifiable_ = true; + num_pages_per_sheet_ = 1; } void PrintSettings::SetPrinterPrintableArea( diff --git a/printing/print_settings.h b/printing/print_settings.h index 569955b6fe5dc6..e6ecec7fa46326 100644 --- a/printing/print_settings.h +++ b/printing/print_settings.h @@ -187,6 +187,11 @@ class PRINTING_EXPORT PrintSettings { void set_is_modifiable(bool is_modifiable) { is_modifiable_ = is_modifiable; } bool is_modifiable() const { return is_modifiable_; } + int num_pages_per_sheet() const { return num_pages_per_sheet_; } + void set_num_pages_per_sheet(int num_pages_per_sheet) { + num_pages_per_sheet_ = num_pages_per_sheet; + } + // Cookie generator. It is used to initialize PrintedDocument with its // associated PrintSettings, to be sure that each generated PrintedPage is // correctly associated with its corresponding PrintedDocument. @@ -262,6 +267,9 @@ class PRINTING_EXPORT PrintSettings { // If margin type is custom, this is what was requested. PageMargins requested_custom_margins_in_points_; + + // Number of pages per sheet. + int num_pages_per_sheet_; }; } // namespace printing diff --git a/printing/print_settings_conversion.cc b/printing/print_settings_conversion.cc index 98caf9c15b7a2a..5bb2923c0cfe9b 100644 --- a/printing/print_settings_conversion.cc +++ b/printing/print_settings_conversion.cc @@ -179,6 +179,7 @@ bool PrintSettingsFromJobSettings(const base::DictionaryValue& job_settings, int copies = 1; int scale_factor = 100; bool rasterize_pdf = false; + int num_pages_per_sheet = 1; if (!job_settings.GetBoolean(kSettingCollate, &collate) || !job_settings.GetInteger(kSettingCopies, &copies) || @@ -216,6 +217,9 @@ bool PrintSettingsFromJobSettings(const base::DictionaryValue& job_settings, #endif } + // TODO(xlou): Add logic to get |num_pages_per_sheet| from |job_settings|. + settings->set_num_pages_per_sheet(num_pages_per_sheet); + return true; } diff --git a/third_party/blink/public/web/web_print_params.h b/third_party/blink/public/web/web_print_params.h index ede7a1ef983ec0..ac54f2ad697af2 100644 --- a/third_party/blink/public/web/web_print_params.h +++ b/third_party/blink/public/web/web_print_params.h @@ -61,10 +61,14 @@ struct WebPrintParams { // Specifies whether printing layout needs to be applied. bool use_printing_layout; + // Specifies how many pages per sheet. This parameter is for N-up mode. + size_t num_pages_per_sheet; + WebPrintParams() : printer_dpi(72), print_scaling_option(kWebPrintScalingOptionFitToPrintableArea), - use_printing_layout(true) {} + use_printing_layout(true), + num_pages_per_sheet(1) {} WebPrintParams(const WebSize& paper_size) : WebPrintParams(paper_size, true) {} @@ -75,20 +79,23 @@ struct WebPrintParams { paper_size(paper_size), printer_dpi(72), print_scaling_option(kWebPrintScalingOptionSourceSize), - use_printing_layout(use_printing_layout) {} + use_printing_layout(use_printing_layout), + num_pages_per_sheet(1) {} WebPrintParams(const WebRect& print_content_area, const WebRect& printable_area, const WebSize& paper_size, int printer_dpi, WebPrintScalingOption print_scaling_option, - bool use_printing_layout) + bool use_printing_layout, + int num_pages_per_sheet) : print_content_area(print_content_area), printable_area(printable_area), paper_size(paper_size), printer_dpi(printer_dpi), print_scaling_option(print_scaling_option), - use_printing_layout(use_printing_layout) {} + use_printing_layout(use_printing_layout), + num_pages_per_sheet(num_pages_per_sheet) {} }; } // namespace blink