[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / chrome / browser / local_discovery / pwg_raster_converter.cc
blob11b6c317ca32294b876ae8cb8bd6db040d9dc1ee
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 "components/cloud_devices/common/cloud_device_description.h"
18 #include "components/cloud_devices/common/printer_description.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/child_process_data.h"
21 #include "content/public/browser/utility_process_host.h"
22 #include "content/public/browser/utility_process_host_client.h"
23 #include "printing/pdf_render_settings.h"
24 #include "printing/pwg_raster_settings.h"
25 #include "printing/units.h"
26 #include "ui/gfx/geometry/rect.h"
27 #include "ui/gfx/geometry/size.h"
29 namespace local_discovery {
31 namespace {
33 using content::BrowserThread;
35 class FileHandlers {
36 public:
37 FileHandlers() {}
39 ~FileHandlers() {
40 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
43 void Init(base::RefCountedMemory* data);
44 bool IsValid();
46 base::FilePath GetPwgPath() const {
47 return temp_dir_.path().AppendASCII("output.pwg");
50 base::FilePath GetPdfPath() const {
51 return temp_dir_.path().AppendASCII("input.pdf");
54 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) {
55 DCHECK(pdf_file_.IsValid());
56 IPC::PlatformFileForTransit transit =
57 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process);
58 return transit;
61 IPC::PlatformFileForTransit GetPwgForProcess(base::ProcessHandle process) {
62 DCHECK(pwg_file_.IsValid());
63 IPC::PlatformFileForTransit transit =
64 IPC::TakeFileHandleForProcess(pwg_file_.Pass(), process);
65 return transit;
68 private:
69 base::ScopedTempDir temp_dir_;
70 base::File pdf_file_;
71 base::File pwg_file_;
74 void FileHandlers::Init(base::RefCountedMemory* data) {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
77 if (!temp_dir_.CreateUniqueTempDir()) {
78 return;
81 if (static_cast<int>(data->size()) !=
82 base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) {
83 return;
86 // Reopen in read only mode.
87 pdf_file_.Initialize(GetPdfPath(),
88 base::File::FLAG_OPEN | base::File::FLAG_READ);
89 pwg_file_.Initialize(GetPwgPath(),
90 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
93 bool FileHandlers::IsValid() {
94 return pdf_file_.IsValid() && pwg_file_.IsValid();
97 // Converts PDF into PWG raster.
98 // Class uses 3 threads: UI, IO and FILE.
99 // Internal workflow is following:
100 // 1. Create instance on the UI thread. (files_, settings_,)
101 // 2. Create file on the FILE thread.
102 // 3. Start utility process and start conversion on the IO thread.
103 // 4. Run result callback on the UI thread.
104 // 5. Instance is destroyed from any thread that has the last reference.
105 // 6. FileHandlers destroyed on the FILE thread.
106 // This step posts |FileHandlers| to be destroyed on the FILE thread.
107 // All these steps work sequentially, so no data should be accessed
108 // simultaneously by several threads.
109 class PwgUtilityProcessHostClient : public content::UtilityProcessHostClient {
110 public:
111 explicit PwgUtilityProcessHostClient(
112 const printing::PdfRenderSettings& settings,
113 const printing::PwgRasterSettings& bitmap_settings);
115 void Convert(base::RefCountedMemory* data,
116 const PWGRasterConverter::ResultCallback& callback);
118 // UtilityProcessHostClient implementation.
119 void OnProcessCrashed(int exit_code) override;
120 bool OnMessageReceived(const IPC::Message& message) override;
122 private:
123 ~PwgUtilityProcessHostClient() override;
125 // Message handlers.
126 void OnProcessStarted();
127 void OnSucceeded();
128 void OnFailed();
130 void RunCallback(bool success);
132 void StartProcessOnIOThread();
134 void RunCallbackOnUIThread(bool success);
135 void OnFilesReadyOnUIThread();
137 scoped_ptr<FileHandlers, BrowserThread::DeleteOnFileThread> files_;
138 printing::PdfRenderSettings settings_;
139 printing::PwgRasterSettings bitmap_settings_;
140 PWGRasterConverter::ResultCallback callback_;
141 base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
143 DISALLOW_COPY_AND_ASSIGN(PwgUtilityProcessHostClient);
146 PwgUtilityProcessHostClient::PwgUtilityProcessHostClient(
147 const printing::PdfRenderSettings& settings,
148 const printing::PwgRasterSettings& bitmap_settings)
149 : settings_(settings), bitmap_settings_(bitmap_settings) {}
151 PwgUtilityProcessHostClient::~PwgUtilityProcessHostClient() {
154 void PwgUtilityProcessHostClient::Convert(
155 base::RefCountedMemory* data,
156 const PWGRasterConverter::ResultCallback& callback) {
157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
158 callback_ = callback;
159 CHECK(!files_);
160 files_.reset(new FileHandlers());
161 BrowserThread::PostTaskAndReply(
162 BrowserThread::FILE, FROM_HERE,
163 base::Bind(&FileHandlers::Init, base::Unretained(files_.get()),
164 make_scoped_refptr(data)),
165 base::Bind(&PwgUtilityProcessHostClient::OnFilesReadyOnUIThread, this));
168 void PwgUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
169 OnFailed();
172 bool PwgUtilityProcessHostClient::OnMessageReceived(
173 const IPC::Message& message) {
174 bool handled = true;
175 IPC_BEGIN_MESSAGE_MAP(PwgUtilityProcessHostClient, message)
176 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted)
177 IPC_MESSAGE_HANDLER(
178 ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded, OnSucceeded)
179 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed,
180 OnFailed)
181 IPC_MESSAGE_UNHANDLED(handled = false)
182 IPC_END_MESSAGE_MAP()
183 return handled;
186 void PwgUtilityProcessHostClient::OnProcessStarted() {
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
188 if (!utility_process_host_) {
189 RunCallbackOnUIThread(false);
190 return;
193 base::ProcessHandle process = utility_process_host_->GetData().handle;
194 utility_process_host_->Send(new ChromeUtilityMsg_RenderPDFPagesToPWGRaster(
195 files_->GetPdfForProcess(process),
196 settings_,
197 bitmap_settings_,
198 files_->GetPwgForProcess(process)));
199 utility_process_host_.reset();
202 void PwgUtilityProcessHostClient::OnSucceeded() {
203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
204 RunCallback(true);
207 void PwgUtilityProcessHostClient::OnFailed() {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
209 RunCallback(false);
212 void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() {
213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
214 if (!files_->IsValid()) {
215 RunCallbackOnUIThread(false);
216 return;
218 BrowserThread::PostTask(
219 BrowserThread::IO, FROM_HERE,
220 base::Bind(&PwgUtilityProcessHostClient::StartProcessOnIOThread, this));
223 void PwgUtilityProcessHostClient::StartProcessOnIOThread() {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
225 utility_process_host_ =
226 content::UtilityProcessHost::Create(
227 this,
228 base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr();
229 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
232 void PwgUtilityProcessHostClient::RunCallback(bool success) {
233 BrowserThread::PostTask(
234 BrowserThread::UI, FROM_HERE,
235 base::Bind(&PwgUtilityProcessHostClient::RunCallbackOnUIThread, this,
236 success));
239 void PwgUtilityProcessHostClient::RunCallbackOnUIThread(bool success) {
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
241 if (!callback_.is_null()) {
242 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
243 base::Bind(callback_, success,
244 files_->GetPwgPath()));
245 callback_.Reset();
249 class PWGRasterConverterImpl : public PWGRasterConverter {
250 public:
251 PWGRasterConverterImpl();
253 ~PWGRasterConverterImpl() override;
255 void Start(base::RefCountedMemory* data,
256 const printing::PdfRenderSettings& conversion_settings,
257 const printing::PwgRasterSettings& bitmap_settings,
258 const ResultCallback& callback) override;
260 private:
261 scoped_refptr<PwgUtilityProcessHostClient> utility_client_;
262 base::CancelableCallback<ResultCallback::RunType> callback_;
264 DISALLOW_COPY_AND_ASSIGN(PWGRasterConverterImpl);
267 PWGRasterConverterImpl::PWGRasterConverterImpl() {
270 PWGRasterConverterImpl::~PWGRasterConverterImpl() {
273 void PWGRasterConverterImpl::Start(
274 base::RefCountedMemory* data,
275 const printing::PdfRenderSettings& conversion_settings,
276 const printing::PwgRasterSettings& bitmap_settings,
277 const ResultCallback& callback) {
278 // Rebind cancelable callback to avoid calling callback if
279 // PWGRasterConverterImpl is destroyed.
280 callback_.Reset(callback);
281 utility_client_ =
282 new PwgUtilityProcessHostClient(conversion_settings, bitmap_settings);
283 utility_client_->Convert(data, callback_.callback());
286 } // namespace
288 // static
289 scoped_ptr<PWGRasterConverter> PWGRasterConverter::CreateDefault() {
290 return scoped_ptr<PWGRasterConverter>(new PWGRasterConverterImpl());
293 // static
294 printing::PdfRenderSettings PWGRasterConverter::GetConversionSettings(
295 const cloud_devices::CloudDeviceDescription& printer_capabilities,
296 const gfx::Size& page_size) {
297 int dpi = printing::kDefaultPdfDpi;
298 cloud_devices::printer::DpiCapability dpis;
299 if (dpis.LoadFrom(printer_capabilities))
300 dpi = std::max(dpis.GetDefault().horizontal, dpis.GetDefault().vertical);
302 double scale = dpi;
303 scale /= printing::kPointsPerInch;
305 // Make vertical rectangle to optimize streaming to printer. Fix orientation
306 // by autorotate.
307 gfx::Rect area(std::min(page_size.width(), page_size.height()) * scale,
308 std::max(page_size.width(), page_size.height()) * scale);
309 return printing::PdfRenderSettings(area, dpi, true /* autorotate */);
312 // static
313 printing::PwgRasterSettings PWGRasterConverter::GetBitmapSettings(
314 const cloud_devices::CloudDeviceDescription& printer_capabilities,
315 const cloud_devices::CloudDeviceDescription& ticket) {
316 printing::PwgRasterSettings result;
317 cloud_devices::printer::PwgRasterConfigCapability raster_capability;
318 // If the raster capability fails to load, raster_capability will contain
319 // the default value.
320 raster_capability.LoadFrom(printer_capabilities);
322 cloud_devices::printer::DuplexTicketItem duplex_item;
323 cloud_devices::printer::DuplexType duplex_value =
324 cloud_devices::printer::NO_DUPLEX;
326 cloud_devices::printer::DocumentSheetBack document_sheet_back =
327 raster_capability.value().document_sheet_back;
329 if (duplex_item.LoadFrom(ticket)) {
330 duplex_value = duplex_item.value();
333 result.odd_page_transform = printing::TRANSFORM_NORMAL;
334 switch (duplex_value) {
335 case cloud_devices::printer::NO_DUPLEX:
336 result.odd_page_transform = printing::TRANSFORM_NORMAL;
337 break;
338 case cloud_devices::printer::LONG_EDGE:
339 if (document_sheet_back == cloud_devices::printer::ROTATED) {
340 result.odd_page_transform = printing::TRANSFORM_ROTATE_180;
341 } else if (document_sheet_back == cloud_devices::printer::FLIPPED) {
342 result.odd_page_transform = printing::TRANSFORM_FLIP_VERTICAL;
344 break;
345 case cloud_devices::printer::SHORT_EDGE:
346 if (document_sheet_back == cloud_devices::printer::MANUAL_TUMBLE) {
347 result.odd_page_transform = printing::TRANSFORM_ROTATE_180;
348 } else if (document_sheet_back == cloud_devices::printer::FLIPPED) {
349 result.odd_page_transform = printing::TRANSFORM_FLIP_HORIZONTAL;
353 result.rotate_all_pages = raster_capability.value().rotate_all_pages;
355 result.reverse_page_order = raster_capability.value().reverse_order_streaming;
356 return result;
359 } // namespace local_discovery