Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / local_discovery / pwg_raster_converter.cc
blobae11a6c88c72af2af02b0ad3e93cdd04bf22c221
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/local_discovery/pwg_raster_converter.h"
7 #include <algorithm>
9 #include "base/bind_helpers.h"
10 #include "base/cancelable_callback.h"
11 #include "base/files/file.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/logging.h"
15 #include "chrome/common/chrome_utility_messages.h"
16 #include "chrome/common/chrome_utility_printing_messages.h"
17 #include "chrome/grit/generated_resources.h"
18 #include "components/cloud_devices/common/cloud_device_description.h"
19 #include "components/cloud_devices/common/printer_description.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/child_process_data.h"
22 #include "content/public/browser/utility_process_host.h"
23 #include "content/public/browser/utility_process_host_client.h"
24 #include "printing/pdf_render_settings.h"
25 #include "printing/pwg_raster_settings.h"
26 #include "printing/units.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/gfx/geometry/rect.h"
29 #include "ui/gfx/geometry/size.h"
31 namespace local_discovery {
33 namespace {
35 using content::BrowserThread;
37 class FileHandlers {
38 public:
39 FileHandlers() {}
41 ~FileHandlers() {
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
45 void Init(base::RefCountedMemory* data);
46 bool IsValid();
48 base::FilePath GetPwgPath() const {
49 return temp_dir_.path().AppendASCII("output.pwg");
52 base::FilePath GetPdfPath() const {
53 return temp_dir_.path().AppendASCII("input.pdf");
56 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) {
57 DCHECK(pdf_file_.IsValid());
58 IPC::PlatformFileForTransit transit =
59 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process);
60 return transit;
63 IPC::PlatformFileForTransit GetPwgForProcess(base::ProcessHandle process) {
64 DCHECK(pwg_file_.IsValid());
65 IPC::PlatformFileForTransit transit =
66 IPC::TakeFileHandleForProcess(pwg_file_.Pass(), process);
67 return transit;
70 private:
71 base::ScopedTempDir temp_dir_;
72 base::File pdf_file_;
73 base::File pwg_file_;
76 void FileHandlers::Init(base::RefCountedMemory* data) {
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
79 if (!temp_dir_.CreateUniqueTempDir()) {
80 return;
83 if (static_cast<int>(data->size()) !=
84 base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) {
85 return;
88 // Reopen in read only mode.
89 pdf_file_.Initialize(GetPdfPath(),
90 base::File::FLAG_OPEN | base::File::FLAG_READ);
91 pwg_file_.Initialize(GetPwgPath(),
92 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
95 bool FileHandlers::IsValid() {
96 return pdf_file_.IsValid() && pwg_file_.IsValid();
99 // Converts PDF into PWG raster.
100 // Class uses 3 threads: UI, IO and FILE.
101 // Internal workflow is following:
102 // 1. Create instance on the UI thread. (files_, settings_,)
103 // 2. Create file on the FILE thread.
104 // 3. Start utility process and start conversion on the IO thread.
105 // 4. Run result callback on the UI thread.
106 // 5. Instance is destroyed from any thread that has the last reference.
107 // 6. FileHandlers destroyed on the FILE thread.
108 // This step posts |FileHandlers| to be destroyed on the FILE thread.
109 // All these steps work sequentially, so no data should be accessed
110 // simultaneously by several threads.
111 class PwgUtilityProcessHostClient : public content::UtilityProcessHostClient {
112 public:
113 explicit PwgUtilityProcessHostClient(
114 const printing::PdfRenderSettings& settings,
115 const printing::PwgRasterSettings& bitmap_settings);
117 void Convert(base::RefCountedMemory* data,
118 const PWGRasterConverter::ResultCallback& callback);
120 // UtilityProcessHostClient implementation.
121 void OnProcessCrashed(int exit_code) override;
122 bool OnMessageReceived(const IPC::Message& message) override;
124 private:
125 ~PwgUtilityProcessHostClient() override;
127 // Message handlers.
128 void OnProcessStarted();
129 void OnSucceeded();
130 void OnFailed();
132 void RunCallback(bool success);
134 void StartProcessOnIOThread();
136 void RunCallbackOnUIThread(bool success);
137 void OnFilesReadyOnUIThread();
139 scoped_ptr<FileHandlers, BrowserThread::DeleteOnFileThread> files_;
140 printing::PdfRenderSettings settings_;
141 printing::PwgRasterSettings bitmap_settings_;
142 PWGRasterConverter::ResultCallback callback_;
143 base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
145 DISALLOW_COPY_AND_ASSIGN(PwgUtilityProcessHostClient);
148 PwgUtilityProcessHostClient::PwgUtilityProcessHostClient(
149 const printing::PdfRenderSettings& settings,
150 const printing::PwgRasterSettings& bitmap_settings)
151 : settings_(settings), bitmap_settings_(bitmap_settings) {}
153 PwgUtilityProcessHostClient::~PwgUtilityProcessHostClient() {
156 void PwgUtilityProcessHostClient::Convert(
157 base::RefCountedMemory* data,
158 const PWGRasterConverter::ResultCallback& callback) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160 callback_ = callback;
161 CHECK(!files_);
162 files_.reset(new FileHandlers());
163 BrowserThread::PostTaskAndReply(
164 BrowserThread::FILE, FROM_HERE,
165 base::Bind(&FileHandlers::Init, base::Unretained(files_.get()),
166 make_scoped_refptr(data)),
167 base::Bind(&PwgUtilityProcessHostClient::OnFilesReadyOnUIThread, this));
170 void PwgUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
171 OnFailed();
174 bool PwgUtilityProcessHostClient::OnMessageReceived(
175 const IPC::Message& message) {
176 bool handled = true;
177 IPC_BEGIN_MESSAGE_MAP(PwgUtilityProcessHostClient, message)
178 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted)
179 IPC_MESSAGE_HANDLER(
180 ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded, OnSucceeded)
181 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed,
182 OnFailed)
183 IPC_MESSAGE_UNHANDLED(handled = false)
184 IPC_END_MESSAGE_MAP()
185 return handled;
188 void PwgUtilityProcessHostClient::OnProcessStarted() {
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
190 if (!utility_process_host_) {
191 RunCallbackOnUIThread(false);
192 return;
195 base::ProcessHandle process = utility_process_host_->GetData().handle;
196 utility_process_host_->Send(new ChromeUtilityMsg_RenderPDFPagesToPWGRaster(
197 files_->GetPdfForProcess(process),
198 settings_,
199 bitmap_settings_,
200 files_->GetPwgForProcess(process)));
201 utility_process_host_.reset();
204 void PwgUtilityProcessHostClient::OnSucceeded() {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
206 RunCallback(true);
209 void PwgUtilityProcessHostClient::OnFailed() {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211 RunCallback(false);
214 void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() {
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
216 if (!files_->IsValid()) {
217 RunCallbackOnUIThread(false);
218 return;
220 BrowserThread::PostTask(
221 BrowserThread::IO, FROM_HERE,
222 base::Bind(&PwgUtilityProcessHostClient::StartProcessOnIOThread, this));
225 void PwgUtilityProcessHostClient::StartProcessOnIOThread() {
226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
227 utility_process_host_ =
228 content::UtilityProcessHost::Create(
229 this,
230 base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr();
231 utility_process_host_->SetName(l10n_util::GetStringUTF16(
232 IDS_UTILITY_PROCESS_PWG_RASTER_CONVERTOR_NAME));
233 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
236 void PwgUtilityProcessHostClient::RunCallback(bool success) {
237 BrowserThread::PostTask(
238 BrowserThread::UI, FROM_HERE,
239 base::Bind(&PwgUtilityProcessHostClient::RunCallbackOnUIThread, this,
240 success));
243 void PwgUtilityProcessHostClient::RunCallbackOnUIThread(bool success) {
244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
245 if (!callback_.is_null()) {
246 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
247 base::Bind(callback_, success,
248 files_->GetPwgPath()));
249 callback_.Reset();
253 class PWGRasterConverterImpl : public PWGRasterConverter {
254 public:
255 PWGRasterConverterImpl();
257 ~PWGRasterConverterImpl() override;
259 void Start(base::RefCountedMemory* data,
260 const printing::PdfRenderSettings& conversion_settings,
261 const printing::PwgRasterSettings& bitmap_settings,
262 const ResultCallback& callback) override;
264 private:
265 scoped_refptr<PwgUtilityProcessHostClient> utility_client_;
266 base::CancelableCallback<ResultCallback::RunType> callback_;
268 DISALLOW_COPY_AND_ASSIGN(PWGRasterConverterImpl);
271 PWGRasterConverterImpl::PWGRasterConverterImpl() {
274 PWGRasterConverterImpl::~PWGRasterConverterImpl() {
277 void PWGRasterConverterImpl::Start(
278 base::RefCountedMemory* data,
279 const printing::PdfRenderSettings& conversion_settings,
280 const printing::PwgRasterSettings& bitmap_settings,
281 const ResultCallback& callback) {
282 // Rebind cancelable callback to avoid calling callback if
283 // PWGRasterConverterImpl is destroyed.
284 callback_.Reset(callback);
285 utility_client_ =
286 new PwgUtilityProcessHostClient(conversion_settings, bitmap_settings);
287 utility_client_->Convert(data, callback_.callback());
290 } // namespace
292 // static
293 scoped_ptr<PWGRasterConverter> PWGRasterConverter::CreateDefault() {
294 return scoped_ptr<PWGRasterConverter>(new PWGRasterConverterImpl());
297 // static
298 printing::PdfRenderSettings PWGRasterConverter::GetConversionSettings(
299 const cloud_devices::CloudDeviceDescription& printer_capabilities,
300 const gfx::Size& page_size) {
301 int dpi = printing::kDefaultPdfDpi;
302 cloud_devices::printer::DpiCapability dpis;
303 if (dpis.LoadFrom(printer_capabilities))
304 dpi = std::max(dpis.GetDefault().horizontal, dpis.GetDefault().vertical);
306 double scale = dpi;
307 scale /= printing::kPointsPerInch;
309 // Make vertical rectangle to optimize streaming to printer. Fix orientation
310 // by autorotate.
311 gfx::Rect area(std::min(page_size.width(), page_size.height()) * scale,
312 std::max(page_size.width(), page_size.height()) * scale);
313 return printing::PdfRenderSettings(area, dpi, true /* autorotate */);
316 // static
317 printing::PwgRasterSettings PWGRasterConverter::GetBitmapSettings(
318 const cloud_devices::CloudDeviceDescription& printer_capabilities,
319 const cloud_devices::CloudDeviceDescription& ticket) {
320 printing::PwgRasterSettings result;
321 cloud_devices::printer::PwgRasterConfigCapability raster_capability;
322 // If the raster capability fails to load, raster_capability will contain
323 // the default value.
324 raster_capability.LoadFrom(printer_capabilities);
326 cloud_devices::printer::DuplexTicketItem duplex_item;
327 cloud_devices::printer::DuplexType duplex_value =
328 cloud_devices::printer::NO_DUPLEX;
330 cloud_devices::printer::DocumentSheetBack document_sheet_back =
331 raster_capability.value().document_sheet_back;
333 if (duplex_item.LoadFrom(ticket)) {
334 duplex_value = duplex_item.value();
337 result.odd_page_transform = printing::TRANSFORM_NORMAL;
338 switch (duplex_value) {
339 case cloud_devices::printer::NO_DUPLEX:
340 result.odd_page_transform = printing::TRANSFORM_NORMAL;
341 break;
342 case cloud_devices::printer::LONG_EDGE:
343 if (document_sheet_back == cloud_devices::printer::ROTATED) {
344 result.odd_page_transform = printing::TRANSFORM_ROTATE_180;
345 } else if (document_sheet_back == cloud_devices::printer::FLIPPED) {
346 result.odd_page_transform = printing::TRANSFORM_FLIP_VERTICAL;
348 break;
349 case cloud_devices::printer::SHORT_EDGE:
350 if (document_sheet_back == cloud_devices::printer::MANUAL_TUMBLE) {
351 result.odd_page_transform = printing::TRANSFORM_ROTATE_180;
352 } else if (document_sheet_back == cloud_devices::printer::FLIPPED) {
353 result.odd_page_transform = printing::TRANSFORM_FLIP_HORIZONTAL;
357 result.rotate_all_pages = raster_capability.value().rotate_all_pages;
359 result.reverse_page_order = raster_capability.value().reverse_order_streaming;
360 return result;
363 } // namespace local_discovery