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(std::string 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_ = PrintParams(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> HeadlessPrintManager::PrintParams( | |
140 HeadlessPrintSettings settings) { | |
141 PrintSettings print_settings; | |
142 print_settings.set_dpi(kPointsPerInch); | |
143 print_settings.set_should_print_backgrounds( | |
144 settings.should_print_backgrounds); | |
145 print_settings.set_scale_factor(settings.scale); | |
146 print_settings.SetOrientation(settings.landscape); | |
147 | |
148 print_settings.set_display_header_footer(settings.display_header_footer); | |
149 if (print_settings.display_header_footer()) { | |
150 url::Replacements<char> url_sanitizer; | |
151 url_sanitizer.ClearUsername(); | |
152 url_sanitizer.ClearPassword(); | |
153 std::string url = printing_rfh_->GetLastCommittedURL() | |
154 .ReplaceComponents(url_sanitizer) | |
155 .spec(); | |
156 print_settings.set_url(base::UTF8ToUTF16(url)); | |
157 } | |
158 | |
159 print_settings.set_margin_type(CUSTOM_MARGINS); | |
160 print_settings.SetCustomMargins(settings.margins_in_points); | |
161 | |
162 gfx::Rect printable_area_device_units(settings.paper_size_in_points); | |
163 print_settings.SetPrinterPrintableArea(settings.paper_size_in_points, | |
164 printable_area_device_units, true); | |
165 | |
166 auto print_params = base::MakeUnique<PrintMsg_PrintPages_Params>(); | |
167 RenderParamsFromPrintSettings(print_settings, &print_params->params); | |
168 print_params->params.document_cookie = PrintSettings::NewCookie(); | |
169 return print_params; | |
170 } | |
171 | |
116 bool HeadlessPrintManager::OnMessageReceived( | 172 bool HeadlessPrintManager::OnMessageReceived( |
117 const IPC::Message& message, | 173 const IPC::Message& message, |
118 content::RenderFrameHost* render_frame_host) { | 174 content::RenderFrameHost* render_frame_host) { |
119 bool handled = true; | 175 bool handled = true; |
120 IPC_BEGIN_MESSAGE_MAP(HeadlessPrintManager, message) | 176 IPC_BEGIN_MESSAGE_MAP(HeadlessPrintManager, message) |
121 IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError, | 177 IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError, |
122 OnShowInvalidPrinterSettingsError) | 178 OnShowInvalidPrinterSettingsError) |
123 IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage) | 179 IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage) |
124 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, | 180 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, |
125 OnGetDefaultPrintSettings) | 181 OnGetDefaultPrintSettings) |
182 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint) | |
126 IPC_MESSAGE_UNHANDLED(handled = false) | 183 IPC_MESSAGE_UNHANDLED(handled = false) |
127 IPC_END_MESSAGE_MAP() | 184 IPC_END_MESSAGE_MAP() |
128 return handled || PrintManager::OnMessageReceived(message, render_frame_host); | 185 return handled || PrintManager::OnMessageReceived(message, render_frame_host); |
129 } | 186 } |
130 | 187 |
131 void HeadlessPrintManager::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { | 188 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, | 189 PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, |
136 print_params); | 190 print_params_->params); |
137 printing_rfh_->Send(reply_msg); | 191 printing_rfh_->Send(reply_msg); |
138 } | 192 } |
139 | 193 |
194 void HeadlessPrintManager::OnScriptedPrint( | |
195 const PrintHostMsg_ScriptedPrint_Params& params, | |
196 IPC::Message* reply_msg) { | |
197 PageRangeStatus status = PageRangeTextToPages( | |
198 page_ranges_text_, params.expected_pages_count, &print_params_->pages); | |
199 switch (status) { | |
200 case SYNTAX_ERROR: | |
201 printing_rfh_->Send(reply_msg); | |
202 ReleaseJob(PAGE_RANGE_SYNTAX_ERROR); | |
203 return; | |
204 case LIMIT_ERROR: | |
205 printing_rfh_->Send(reply_msg); | |
206 ReleaseJob(PAGE_COUNT_EXCEEDED); | |
207 return; | |
208 default: | |
Eric Seckler
2017/05/02 09:35:27
nit: make this a "case SUCCESS:" or alike and add
jzfeng
2017/05/03 00:45:56
Done.
| |
209 PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, *print_params_); | |
210 printing_rfh_->Send(reply_msg); | |
211 return; | |
212 } | |
213 } | |
214 | |
140 void HeadlessPrintManager::OnShowInvalidPrinterSettingsError() { | 215 void HeadlessPrintManager::OnShowInvalidPrinterSettingsError() { |
141 ReleaseJob(INVALID_PRINTER_SETTINGS); | 216 ReleaseJob(INVALID_PRINTER_SETTINGS); |
142 } | 217 } |
143 | 218 |
144 void HeadlessPrintManager::OnPrintingFailed(int cookie) { | 219 void HeadlessPrintManager::OnPrintingFailed(int cookie) { |
145 ReleaseJob(PRINTING_FAILED); | 220 ReleaseJob(PRINTING_FAILED); |
146 } | 221 } |
147 | 222 |
223 void HeadlessPrintManager::OnDidGetPrintedPagesCount(int cookie, | |
224 int number_pages) { | |
225 PrintManager::OnDidGetPrintedPagesCount(cookie, number_pages); | |
226 if (!print_params_->pages.empty()) | |
227 number_pages_ = print_params_->pages.size(); | |
228 } | |
229 | |
148 void HeadlessPrintManager::OnDidPrintPage( | 230 void HeadlessPrintManager::OnDidPrintPage( |
149 const PrintHostMsg_DidPrintPage_Params& params) { | 231 const PrintHostMsg_DidPrintPage_Params& params) { |
150 if (!callback_) { | 232 if (!callback_) { |
151 DLOG(ERROR) | 233 DLOG(ERROR) |
152 << "Unexpected PrintHostMsg_DidPrintPage message from the renderer"; | 234 << "Unexpected PrintHostMsg_DidPrintPage message from the renderer"; |
153 return; | 235 return; |
154 } | 236 } |
155 | 237 |
156 const bool metafile_must_be_valid = expecting_first_page_; | 238 const bool metafile_must_be_valid = expecting_first_page_; |
157 expecting_first_page_ = false; | 239 expecting_first_page_ = false; |
(...skipping 28 matching lines...) Expand all Loading... | |
186 } | 268 } |
187 } | 269 } |
188 | 270 |
189 if (--number_pages_ == 0) | 271 if (--number_pages_ == 0) |
190 ReleaseJob(PRINT_SUCCESS); | 272 ReleaseJob(PRINT_SUCCESS); |
191 } | 273 } |
192 | 274 |
193 void HeadlessPrintManager::Reset() { | 275 void HeadlessPrintManager::Reset() { |
194 printing_rfh_ = nullptr; | 276 printing_rfh_ = nullptr; |
195 callback_.Reset(); | 277 callback_.Reset(); |
278 print_params_.reset(); | |
279 page_ranges_text_.clear(); | |
196 data_.clear(); | 280 data_.clear(); |
197 expecting_first_page_ = true; | 281 expecting_first_page_ = true; |
198 number_pages_ = 0; | 282 number_pages_ = 0; |
199 } | 283 } |
200 | 284 |
201 void HeadlessPrintManager::ReleaseJob(PrintResult result) { | 285 void HeadlessPrintManager::ReleaseJob(PrintResult result) { |
202 if (!callback_) { | 286 if (!callback_) { |
203 DLOG(ERROR) << "ReleaseJob is called when callback_ is null. Check whether " | 287 DLOG(ERROR) << "ReleaseJob is called when callback_ is null. Check whether " |
204 "ReleaseJob is called more than once."; | 288 "ReleaseJob is called more than once."; |
205 return; | 289 return; |
206 } | 290 } |
207 | 291 |
208 if (result == PRINT_SUCCESS) | 292 if (result == PRINT_SUCCESS) |
209 callback_.Run(result, std::move(data_)); | 293 callback_.Run(result, std::move(data_)); |
210 else | 294 else |
211 callback_.Run(result, std::string()); | 295 callback_.Run(result, std::string()); |
212 printing_rfh_->Send(new PrintMsg_PrintingDone(printing_rfh_->GetRoutingID(), | 296 printing_rfh_->Send(new PrintMsg_PrintingDone(printing_rfh_->GetRoutingID(), |
213 result == PRINT_SUCCESS)); | 297 result == PRINT_SUCCESS)); |
214 Reset(); | 298 Reset(); |
215 } | 299 } |
216 | 300 |
217 } // namespace printing | 301 } // namespace printing |
OLD | NEW |