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 |