| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "headless/lib/browser/headless_print_manager.h" | 5 #include "headless/lib/browser/headless_print_manager.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/base64.h" | 10 #include "base/base64.h" |
| 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/string_piece.h" |
| 14 #include "base/strings/string_split.h" |
| 15 #include "base/strings/utf_string_conversions.h" |
| 11 #include "components/printing/browser/print_manager_utils.h" | 16 #include "components/printing/browser/print_manager_utils.h" |
| 12 #include "components/printing/common/print_messages.h" | 17 #include "components/printing/common/print_messages.h" |
| 13 #include "printing/pdf_metafile_skia.h" | 18 #include "printing/pdf_metafile_skia.h" |
| 14 #include "printing/print_settings.h" | 19 #include "printing/print_job_constants.h" |
| 15 #include "printing/units.h" | 20 #include "printing/units.h" |
| 16 | 21 |
| 17 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::HeadlessPrintManager); | 22 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::HeadlessPrintManager); |
| 18 | 23 |
| 19 namespace printing { | 24 namespace printing { |
| 20 | 25 |
| 21 namespace { | |
| 22 | |
| 23 // TODO(jzfeng): let the print settings to be configurable. | |
| 24 const double kTopMarginInInch = 0.25; | |
| 25 const double kBottomMarginInInch = 0.56; | |
| 26 const double kLeftMarginInInch = 0.25; | |
| 27 const double kRightMarginInInch = 0.25; | |
| 28 | |
| 29 PrintSettings GetDefaultPDFPrinterSettings() { | |
| 30 #if defined(OS_MACOSX) | |
| 31 // On the Mac, the printable area is in points, use kPointsPerInch to compute | |
| 32 // its bounds. | |
| 33 int dpi = kPointsPerInch; | |
| 34 #else | |
| 35 int dpi = kDefaultPdfDpi; | |
| 36 #endif | |
| 37 gfx::Size physical_size_device_units; | |
| 38 gfx::Rect printable_area_device_units; | |
| 39 double page_width_in_pixel = kLetterWidthInch * dpi; | |
| 40 double page_height_in_pixel = kLetterHeightInch * dpi; | |
| 41 physical_size_device_units.SetSize(static_cast<int>(page_width_in_pixel), | |
| 42 static_cast<int>(page_height_in_pixel)); | |
| 43 printable_area_device_units.SetRect( | |
| 44 static_cast<int>(kLeftMarginInInch * dpi), | |
| 45 static_cast<int>(kTopMarginInInch * dpi), | |
| 46 page_width_in_pixel - (kLeftMarginInInch + kRightMarginInInch) * dpi, | |
| 47 page_height_in_pixel - (kTopMarginInInch + kBottomMarginInInch) * dpi); | |
| 48 | |
| 49 PrintSettings settings; | |
| 50 settings.set_dpi(dpi); | |
| 51 settings.SetPrinterPrintableArea(physical_size_device_units, | |
| 52 printable_area_device_units, true); | |
| 53 settings.set_should_print_backgrounds(true); | |
| 54 return settings; | |
| 55 } | |
| 56 | |
| 57 } // namespace | |
| 58 | |
| 59 HeadlessPrintManager::HeadlessPrintManager(content::WebContents* web_contents) | 26 HeadlessPrintManager::HeadlessPrintManager(content::WebContents* web_contents) |
| 60 : PrintManager(web_contents) { | 27 : PrintManager(web_contents) { |
| 61 Reset(); | 28 Reset(); |
| 62 } | 29 } |
| 63 | 30 |
| 64 HeadlessPrintManager::~HeadlessPrintManager() {} | 31 HeadlessPrintManager::~HeadlessPrintManager() {} |
| 65 | 32 |
| 66 // static | 33 // static |
| 67 std::string HeadlessPrintManager::PrintResultToString(PrintResult result) { | 34 std::string HeadlessPrintManager::PrintResultToString(PrintResult result) { |
| 68 switch (result) { | 35 switch (result) { |
| 69 case PRINT_SUCCESS: | 36 case PRINT_SUCCESS: |
| 70 return std::string(); // no error message | 37 return std::string(); // no error message |
| 71 case PRINTING_FAILED: | 38 case PRINTING_FAILED: |
| 72 return "Printing failed"; | 39 return "Printing failed"; |
| 73 case INVALID_PRINTER_SETTINGS: | 40 case INVALID_PRINTER_SETTINGS: |
| 74 return "Show invalid printer settings error"; | 41 return "Show invalid printer settings error"; |
| 75 case INVALID_MEMORY_HANDLE: | 42 case INVALID_MEMORY_HANDLE: |
| 76 return "Invalid memory handle"; | 43 return "Invalid memory handle"; |
| 77 case METAFILE_MAP_ERROR: | 44 case METAFILE_MAP_ERROR: |
| 78 return "Map to shared memory error"; | 45 return "Map to shared memory error"; |
| 79 case UNEXPECTED_VALID_MEMORY_HANDLE: | 46 case UNEXPECTED_VALID_MEMORY_HANDLE: |
| 80 return "Unexpected valide memory handle"; | 47 return "Unexpected valide memory handle"; |
| 81 case METAFILE_INVALID_HEADER: | 48 case METAFILE_INVALID_HEADER: |
| 82 return "Invalid metafile header"; | 49 return "Invalid metafile header"; |
| 83 case METAFILE_GET_DATA_ERROR: | 50 case METAFILE_GET_DATA_ERROR: |
| 84 return "Get data from metafile error"; | 51 return "Get data from metafile error"; |
| 85 case SIMULTANEOUS_PRINT_ACTIVE: | 52 case SIMULTANEOUS_PRINT_ACTIVE: |
| 86 return "The previous printing job hasn't finished"; | 53 return "The previous printing job hasn't finished"; |
| 54 case PAGE_RANGE_SYNTAX_ERROR: |
| 55 return "Page range syntax error"; |
| 56 case PAGE_COUNT_EXCEEDED: |
| 57 return "Page range exceeds page count"; |
| 87 default: | 58 default: |
| 88 NOTREACHED(); | 59 NOTREACHED(); |
| 89 return "Unknown PrintResult"; | 60 return "Unknown PrintResult"; |
| 90 } | 61 } |
| 91 } | 62 } |
| 92 | 63 |
| 93 // static | 64 // static |
| 94 std::unique_ptr<base::DictionaryValue> | 65 std::unique_ptr<base::DictionaryValue> |
| 95 HeadlessPrintManager::PDFContentsToDictionaryValue(const std::string& data) { | 66 HeadlessPrintManager::PDFContentsToDictionaryValue(const std::string& data) { |
| 96 std::string base_64_data; | 67 std::string base_64_data; |
| 97 base::Base64Encode(data, &base_64_data); | 68 base::Base64Encode(data, &base_64_data); |
| 98 auto result = base::MakeUnique<base::DictionaryValue>(); | 69 auto result = base::MakeUnique<base::DictionaryValue>(); |
| 99 result->SetString("data", base_64_data); | 70 result->SetString("data", base_64_data); |
| 100 return result; | 71 return result; |
| 101 } | 72 } |
| 102 | 73 |
| 74 // static |
| 75 HeadlessPrintManager::PageRangeStatus |
| 76 HeadlessPrintManager::PageRangeTextToPages(base::StringPiece page_range_text, |
| 77 int pages_count, |
| 78 std::vector<int>* pages) { |
| 79 PageRanges page_ranges; |
| 80 for (const auto& range_string : |
| 81 base::SplitStringPiece(page_range_text, ",", base::TRIM_WHITESPACE, |
| 82 base::SPLIT_WANT_NONEMPTY)) { |
| 83 printing::PageRange range; |
| 84 if (range_string.find("-") == base::StringPiece::npos) { |
| 85 if (!base::StringToInt(range_string, &range.from)) |
| 86 return SYNTAX_ERROR; |
| 87 range.to = range.from; |
| 88 } else if (range_string == "-") { |
| 89 range.from = 1; |
| 90 range.to = pages_count; |
| 91 } else if (range_string.starts_with("-")) { |
| 92 range.from = 1; |
| 93 if (!base::StringToInt(range_string.substr(1), &range.to)) |
| 94 return SYNTAX_ERROR; |
| 95 } else if (range_string.ends_with("-")) { |
| 96 range.to = pages_count; |
| 97 if (!base::StringToInt(range_string.substr(0, range_string.length() - 1), |
| 98 &range.from)) |
| 99 return SYNTAX_ERROR; |
| 100 } else { |
| 101 auto tokens = base::SplitStringPiece( |
| 102 range_string, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 103 if (tokens.size() != 2 || !base::StringToInt(tokens[0], &range.from) || |
| 104 !base::StringToInt(tokens[1], &range.to)) |
| 105 return SYNTAX_ERROR; |
| 106 } |
| 107 |
| 108 if (range.from < 1 || range.from > range.to) |
| 109 return SYNTAX_ERROR; |
| 110 if (range.to > pages_count) |
| 111 return LIMIT_ERROR; |
| 112 |
| 113 // Page numbers are 1-based in the dictionary. |
| 114 // Page numbers are 0-based for the print settings. |
| 115 range.from--; |
| 116 range.to--; |
| 117 page_ranges.push_back(range); |
| 118 } |
| 119 *pages = PageRange::GetPages(page_ranges); |
| 120 return NO_ERROR; |
| 121 } |
| 122 |
| 103 void HeadlessPrintManager::GetPDFContents(content::RenderFrameHost* rfh, | 123 void HeadlessPrintManager::GetPDFContents(content::RenderFrameHost* rfh, |
| 124 const HeadlessPrintSettings& settings, |
| 104 const GetPDFCallback& callback) { | 125 const GetPDFCallback& callback) { |
| 105 DCHECK(callback); | 126 DCHECK(callback); |
| 106 | 127 |
| 107 if (callback_) { | 128 if (callback_) { |
| 108 callback.Run(SIMULTANEOUS_PRINT_ACTIVE, std::string()); | 129 callback.Run(SIMULTANEOUS_PRINT_ACTIVE, std::string()); |
| 109 return; | 130 return; |
| 110 } | 131 } |
| 111 printing_rfh_ = rfh; | 132 printing_rfh_ = rfh; |
| 112 callback_ = callback; | 133 callback_ = callback; |
| 134 print_params_ = GetPrintParamsFromSettings(settings); |
| 135 page_ranges_text_ = settings.page_ranges; |
| 113 rfh->Send(new PrintMsg_PrintPages(rfh->GetRoutingID())); | 136 rfh->Send(new PrintMsg_PrintPages(rfh->GetRoutingID())); |
| 114 } | 137 } |
| 115 | 138 |
| 139 std::unique_ptr<PrintMsg_PrintPages_Params> |
| 140 HeadlessPrintManager::GetPrintParamsFromSettings( |
| 141 const HeadlessPrintSettings& settings) { |
| 142 PrintSettings print_settings; |
| 143 print_settings.set_dpi(kPointsPerInch); |
| 144 print_settings.set_should_print_backgrounds( |
| 145 settings.should_print_backgrounds); |
| 146 print_settings.set_scale_factor(settings.scale); |
| 147 print_settings.SetOrientation(settings.landscape); |
| 148 |
| 149 print_settings.set_display_header_footer(settings.display_header_footer); |
| 150 if (print_settings.display_header_footer()) { |
| 151 url::Replacements<char> url_sanitizer; |
| 152 url_sanitizer.ClearUsername(); |
| 153 url_sanitizer.ClearPassword(); |
| 154 std::string url = printing_rfh_->GetLastCommittedURL() |
| 155 .ReplaceComponents(url_sanitizer) |
| 156 .spec(); |
| 157 print_settings.set_url(base::UTF8ToUTF16(url)); |
| 158 } |
| 159 |
| 160 print_settings.set_margin_type(CUSTOM_MARGINS); |
| 161 print_settings.SetCustomMargins(settings.margins_in_points); |
| 162 |
| 163 gfx::Rect printable_area_device_units(settings.paper_size_in_points); |
| 164 print_settings.SetPrinterPrintableArea(settings.paper_size_in_points, |
| 165 printable_area_device_units, true); |
| 166 |
| 167 auto print_params = base::MakeUnique<PrintMsg_PrintPages_Params>(); |
| 168 RenderParamsFromPrintSettings(print_settings, &print_params->params); |
| 169 print_params->params.document_cookie = PrintSettings::NewCookie(); |
| 170 return print_params; |
| 171 } |
| 172 |
| 116 bool HeadlessPrintManager::OnMessageReceived( | 173 bool HeadlessPrintManager::OnMessageReceived( |
| 117 const IPC::Message& message, | 174 const IPC::Message& message, |
| 118 content::RenderFrameHost* render_frame_host) { | 175 content::RenderFrameHost* render_frame_host) { |
| 119 bool handled = true; | 176 bool handled = true; |
| 120 IPC_BEGIN_MESSAGE_MAP(HeadlessPrintManager, message) | 177 IPC_BEGIN_MESSAGE_MAP(HeadlessPrintManager, message) |
| 121 IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError, | 178 IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError, |
| 122 OnShowInvalidPrinterSettingsError) | 179 OnShowInvalidPrinterSettingsError) |
| 123 IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage) | 180 IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage) |
| 124 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, | 181 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, |
| 125 OnGetDefaultPrintSettings) | 182 OnGetDefaultPrintSettings) |
| 183 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint) |
| 126 IPC_MESSAGE_UNHANDLED(handled = false) | 184 IPC_MESSAGE_UNHANDLED(handled = false) |
| 127 IPC_END_MESSAGE_MAP() | 185 IPC_END_MESSAGE_MAP() |
| 128 return handled || PrintManager::OnMessageReceived(message, render_frame_host); | 186 return handled || PrintManager::OnMessageReceived(message, render_frame_host); |
| 129 } | 187 } |
| 130 | 188 |
| 131 void HeadlessPrintManager::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { | 189 void HeadlessPrintManager::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { |
| 132 PrintMsg_Print_Params print_params; | |
| 133 RenderParamsFromPrintSettings(GetDefaultPDFPrinterSettings(), &print_params); | |
| 134 print_params.document_cookie = PrintSettings::NewCookie(); | |
| 135 PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, | 190 PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, |
| 136 print_params); | 191 print_params_->params); |
| 137 printing_rfh_->Send(reply_msg); | 192 printing_rfh_->Send(reply_msg); |
| 138 } | 193 } |
| 139 | 194 |
| 195 void HeadlessPrintManager::OnScriptedPrint( |
| 196 const PrintHostMsg_ScriptedPrint_Params& params, |
| 197 IPC::Message* reply_msg) { |
| 198 PageRangeStatus status = PageRangeTextToPages( |
| 199 page_ranges_text_, params.expected_pages_count, &print_params_->pages); |
| 200 switch (status) { |
| 201 case SYNTAX_ERROR: |
| 202 printing_rfh_->Send(reply_msg); |
| 203 ReleaseJob(PAGE_RANGE_SYNTAX_ERROR); |
| 204 return; |
| 205 case LIMIT_ERROR: |
| 206 printing_rfh_->Send(reply_msg); |
| 207 ReleaseJob(PAGE_COUNT_EXCEEDED); |
| 208 return; |
| 209 case NO_ERROR: |
| 210 PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, *print_params_); |
| 211 printing_rfh_->Send(reply_msg); |
| 212 return; |
| 213 default: |
| 214 NOTREACHED(); |
| 215 return; |
| 216 } |
| 217 } |
| 218 |
| 140 void HeadlessPrintManager::OnShowInvalidPrinterSettingsError() { | 219 void HeadlessPrintManager::OnShowInvalidPrinterSettingsError() { |
| 141 ReleaseJob(INVALID_PRINTER_SETTINGS); | 220 ReleaseJob(INVALID_PRINTER_SETTINGS); |
| 142 } | 221 } |
| 143 | 222 |
| 144 void HeadlessPrintManager::OnPrintingFailed(int cookie) { | 223 void HeadlessPrintManager::OnPrintingFailed(int cookie) { |
| 145 ReleaseJob(PRINTING_FAILED); | 224 ReleaseJob(PRINTING_FAILED); |
| 146 } | 225 } |
| 147 | 226 |
| 227 void HeadlessPrintManager::OnDidGetPrintedPagesCount(int cookie, |
| 228 int number_pages) { |
| 229 PrintManager::OnDidGetPrintedPagesCount(cookie, number_pages); |
| 230 if (!print_params_->pages.empty()) |
| 231 number_pages_ = print_params_->pages.size(); |
| 232 } |
| 233 |
| 148 void HeadlessPrintManager::OnDidPrintPage( | 234 void HeadlessPrintManager::OnDidPrintPage( |
| 149 const PrintHostMsg_DidPrintPage_Params& params) { | 235 const PrintHostMsg_DidPrintPage_Params& params) { |
| 150 if (!callback_) { | 236 if (!callback_) { |
| 151 DLOG(ERROR) | 237 DLOG(ERROR) |
| 152 << "Unexpected PrintHostMsg_DidPrintPage message from the renderer"; | 238 << "Unexpected PrintHostMsg_DidPrintPage message from the renderer"; |
| 153 return; | 239 return; |
| 154 } | 240 } |
| 155 | 241 |
| 156 const bool metafile_must_be_valid = expecting_first_page_; | 242 const bool metafile_must_be_valid = expecting_first_page_; |
| 157 expecting_first_page_ = false; | 243 expecting_first_page_ = false; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 186 } | 272 } |
| 187 } | 273 } |
| 188 | 274 |
| 189 if (--number_pages_ == 0) | 275 if (--number_pages_ == 0) |
| 190 ReleaseJob(PRINT_SUCCESS); | 276 ReleaseJob(PRINT_SUCCESS); |
| 191 } | 277 } |
| 192 | 278 |
| 193 void HeadlessPrintManager::Reset() { | 279 void HeadlessPrintManager::Reset() { |
| 194 printing_rfh_ = nullptr; | 280 printing_rfh_ = nullptr; |
| 195 callback_.Reset(); | 281 callback_.Reset(); |
| 282 print_params_.reset(); |
| 283 page_ranges_text_.clear(); |
| 196 data_.clear(); | 284 data_.clear(); |
| 197 expecting_first_page_ = true; | 285 expecting_first_page_ = true; |
| 198 number_pages_ = 0; | 286 number_pages_ = 0; |
| 199 } | 287 } |
| 200 | 288 |
| 201 void HeadlessPrintManager::ReleaseJob(PrintResult result) { | 289 void HeadlessPrintManager::ReleaseJob(PrintResult result) { |
| 202 if (!callback_) { | 290 if (!callback_) { |
| 203 DLOG(ERROR) << "ReleaseJob is called when callback_ is null. Check whether " | 291 DLOG(ERROR) << "ReleaseJob is called when callback_ is null. Check whether " |
| 204 "ReleaseJob is called more than once."; | 292 "ReleaseJob is called more than once."; |
| 205 return; | 293 return; |
| 206 } | 294 } |
| 207 | 295 |
| 208 if (result == PRINT_SUCCESS) | 296 if (result == PRINT_SUCCESS) |
| 209 callback_.Run(result, std::move(data_)); | 297 callback_.Run(result, std::move(data_)); |
| 210 else | 298 else |
| 211 callback_.Run(result, std::string()); | 299 callback_.Run(result, std::string()); |
| 212 printing_rfh_->Send(new PrintMsg_PrintingDone(printing_rfh_->GetRoutingID(), | 300 printing_rfh_->Send(new PrintMsg_PrintingDone(printing_rfh_->GetRoutingID(), |
| 213 result == PRINT_SUCCESS)); | 301 result == PRINT_SUCCESS)); |
| 214 Reset(); | 302 Reset(); |
| 215 } | 303 } |
| 216 | 304 |
| 217 } // namespace printing | 305 } // namespace printing |
| OLD | NEW |