Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / local_discovery / pwg_raster_converter.cc
blobe6109d0f33d1bfef30dc411f99e158d39a442c73
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 "base/bind_helpers.h"
8 #include "base/cancelable_callback.h"
9 #include "base/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/logging.h"
12 #include "chrome/common/chrome_utility_messages.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/child_process_data.h"
15 #include "content/public/browser/utility_process_host.h"
16 #include "content/public/browser/utility_process_host_client.h"
18 namespace local_discovery {
20 namespace {
22 using content::BrowserThread;
24 class FileHandlers {
25 public:
26 FileHandlers() : pdf_file_(base::kInvalidPlatformFileValue),
27 pwg_file_(base::kInvalidPlatformFileValue) { }
29 ~FileHandlers() {
30 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
31 if (pdf_file_ != base::kInvalidPlatformFileValue)
32 base::ClosePlatformFile(pdf_file_);
33 if (pwg_file_ != base::kInvalidPlatformFileValue)
34 base::ClosePlatformFile(pwg_file_);
37 void Init(base::RefCountedMemory* data);
38 bool IsValid();
40 base::FilePath GetPwgPath() const {
41 return temp_dir_.path().AppendASCII("output.pwg");
44 base::FilePath GetPdfPath() const {
45 return temp_dir_.path().AppendASCII("input.pdf");
48 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) {
49 DCHECK_NE(pdf_file_, base::kInvalidPlatformFileValue);
50 IPC::PlatformFileForTransit transit =
51 IPC::GetFileHandleForProcess(pdf_file_, process, true);
52 pdf_file_ = base::kInvalidPlatformFileValue;
53 return transit;
56 IPC::PlatformFileForTransit GetPwgForProcess(base::ProcessHandle process) {
57 DCHECK_NE(pwg_file_, base::kInvalidPlatformFileValue);
58 IPC::PlatformFileForTransit transit =
59 IPC::GetFileHandleForProcess(pwg_file_, process, true);
60 pwg_file_ = base::kInvalidPlatformFileValue;
61 return transit;
64 private:
65 base::ScopedTempDir temp_dir_;
66 base::PlatformFile pdf_file_;
67 base::PlatformFile pwg_file_;
70 void FileHandlers::Init(base::RefCountedMemory* data) {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
73 if (!temp_dir_.CreateUniqueTempDir()) {
74 return;
77 if (static_cast<int>(data->size()) !=
78 file_util::WriteFile(GetPdfPath(),
79 reinterpret_cast<const char*>(data->front()),
80 data->size())) {
81 return;
84 // Reopen in read only mode.
85 pdf_file_ = base::CreatePlatformFile(GetPdfPath(), base::PLATFORM_FILE_OPEN |
86 base::PLATFORM_FILE_READ,
87 NULL, NULL);
88 pwg_file_ = base::CreatePlatformFile(GetPwgPath(),
89 base::PLATFORM_FILE_CREATE_ALWAYS |
90 base::PLATFORM_FILE_APPEND, NULL, NULL);
93 bool FileHandlers::IsValid() {
94 return pdf_file_ != base::kInvalidPlatformFileValue &&
95 pwg_file_ != base::kInvalidPlatformFileValue;
98 // Converts PDF into PWG raster.
99 // Class uses 3 threads: UI, IO and FILE.
100 // Internal workflow is following:
101 // 1. Create instance on the UI thread. (files_, settings_,)
102 // 2. Create file on the FILE thread.
103 // 3. Start utility process and start conversion on the IO thread.
104 // 4. Run result callback on the UI thread.
105 // 5. Instance is destroyed from any thread that has the last reference.
106 // 6. FileHandlers destroyed on the FILE thread.
107 // This step posts |FileHandlers| to be destroyed on the FILE thread.
108 // All these steps work sequentially, so no data should be accessed
109 // simultaneously by several threads.
110 class PwgUtilityProcessHostClient : public content::UtilityProcessHostClient {
111 public:
112 explicit PwgUtilityProcessHostClient(
113 const printing::PdfRenderSettings& settings);
115 void Convert(base::RefCountedMemory* data,
116 const PWGRasterConverter::ResultCallback& callback);
118 // UtilityProcessHostClient implementation.
119 virtual void OnProcessCrashed(int exit_code) OVERRIDE;
120 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
122 private:
123 virtual ~PwgUtilityProcessHostClient();
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> files_;
138 printing::PdfRenderSettings settings_;
139 PWGRasterConverter::ResultCallback callback_;
140 base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
142 DISALLOW_COPY_AND_ASSIGN(PwgUtilityProcessHostClient);
145 PwgUtilityProcessHostClient::PwgUtilityProcessHostClient(
146 const printing::PdfRenderSettings& settings) : settings_(settings) {
149 PwgUtilityProcessHostClient::~PwgUtilityProcessHostClient() {
150 // Delete temp directory.
151 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, files_.release());
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(
195 new ChromeUtilityMsg_RenderPDFPagesToPWGRaster(
196 files_->GetPdfForProcess(process),
197 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 virtual ~PWGRasterConverterImpl();
255 virtual void Start(base::RefCountedMemory* data,
256 const printing::PdfRenderSettings& conversion_settings,
257 const ResultCallback& callback) OVERRIDE;
258 private:
259 scoped_refptr<PwgUtilityProcessHostClient> utility_client_;
260 base::CancelableCallback<ResultCallback::RunType> callback_;
262 DISALLOW_COPY_AND_ASSIGN(PWGRasterConverterImpl);
265 PWGRasterConverterImpl::PWGRasterConverterImpl() {
268 PWGRasterConverterImpl::~PWGRasterConverterImpl() {
271 void PWGRasterConverterImpl::Start(
272 base::RefCountedMemory* data,
273 const printing::PdfRenderSettings& conversion_settings,
274 const ResultCallback& callback) {
275 // Rebind cancelable callback to avoid calling callback if
276 // PWGRasterConverterImpl is destroyed.
277 callback_.Reset(callback);
278 utility_client_ = new PwgUtilityProcessHostClient(conversion_settings);
279 utility_client_->Convert(data, callback_.callback());
282 } // namespace
284 // static
285 scoped_ptr<PWGRasterConverter> PWGRasterConverter::CreateDefault() {
286 return scoped_ptr<PWGRasterConverter>(new PWGRasterConverterImpl());
289 } // namespace local_discovery