Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / local_discovery / pwg_raster_converter.cc
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.
4
5 #include "chrome/browser/local_discovery/pwg_raster_converter.h"
6
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"
17
18 namespace local_discovery {
19
20 namespace {
21
22 using content::BrowserThread;
23
24 class FileHandlers {
25  public:
26   FileHandlers() : pdf_file_(base::kInvalidPlatformFileValue),
27                    pwg_file_(base::kInvalidPlatformFileValue) { }
28
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_);
35   }
36
37   void Init(base::RefCountedMemory* data);
38   bool IsValid();
39
40   base::FilePath GetPwgPath() const {
41     return temp_dir_.path().AppendASCII("output.pwg");
42   }
43
44   base::FilePath GetPdfPath() const {
45     return temp_dir_.path().AppendASCII("input.pdf");
46   }
47
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;
54   }
55
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;
62   }
63
64  private:
65   base::ScopedTempDir temp_dir_;
66   base::PlatformFile pdf_file_;
67   base::PlatformFile pwg_file_;
68 };
69
70 void FileHandlers::Init(base::RefCountedMemory* data) {
71   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
72
73   if (!temp_dir_.CreateUniqueTempDir()) {
74     return;
75   }
76
77   if (static_cast<int>(data->size()) !=
78       base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) {
79     return;
80   }
81
82   // Reopen in read only mode.
83   pdf_file_ = base::CreatePlatformFile(GetPdfPath(), base::PLATFORM_FILE_OPEN |
84                                                      base::PLATFORM_FILE_READ,
85                                        NULL, NULL);
86   pwg_file_ = base::CreatePlatformFile(GetPwgPath(),
87                                        base::PLATFORM_FILE_CREATE_ALWAYS |
88                                        base::PLATFORM_FILE_APPEND, NULL, NULL);
89 }
90
91 bool FileHandlers::IsValid() {
92   return pdf_file_ != base::kInvalidPlatformFileValue &&
93          pwg_file_ != base::kInvalidPlatformFileValue;
94 }
95
96 // Converts PDF into PWG raster.
97 // Class uses 3 threads: UI, IO and FILE.
98 // Internal workflow is following:
99 // 1. Create instance on the UI thread. (files_, settings_,)
100 // 2. Create file on the FILE thread.
101 // 3. Start utility process and start conversion on the IO thread.
102 // 4. Run result callback on the UI thread.
103 // 5. Instance is destroyed from any thread that has the last reference.
104 // 6. FileHandlers destroyed on the FILE thread.
105 //    This step posts |FileHandlers| to be destroyed on the FILE thread.
106 // All these steps work sequentially, so no data should be accessed
107 // simultaneously by several threads.
108 class PwgUtilityProcessHostClient : public content::UtilityProcessHostClient {
109  public:
110   explicit PwgUtilityProcessHostClient(
111       const printing::PdfRenderSettings& settings,
112       const printing::PwgRasterSettings& bitmap_settings);
113
114   void Convert(base::RefCountedMemory* data,
115                const PWGRasterConverter::ResultCallback& callback);
116
117   // UtilityProcessHostClient implementation.
118   virtual void OnProcessCrashed(int exit_code) OVERRIDE;
119   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
120
121  private:
122   virtual ~PwgUtilityProcessHostClient();
123
124   // Message handlers.
125   void OnProcessStarted();
126   void OnSucceeded();
127   void OnFailed();
128
129   void RunCallback(bool success);
130
131   void StartProcessOnIOThread();
132
133   void RunCallbackOnUIThread(bool success);
134   void OnFilesReadyOnUIThread();
135
136   scoped_ptr<FileHandlers> files_;
137   printing::PdfRenderSettings settings_;
138   printing::PwgRasterSettings bitmap_settings_;
139   PWGRasterConverter::ResultCallback callback_;
140   base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
141
142   DISALLOW_COPY_AND_ASSIGN(PwgUtilityProcessHostClient);
143 };
144
145 PwgUtilityProcessHostClient::PwgUtilityProcessHostClient(
146     const printing::PdfRenderSettings& settings,
147     const printing::PwgRasterSettings& bitmap_settings)
148     : settings_(settings), bitmap_settings_(bitmap_settings) {}
149
150 PwgUtilityProcessHostClient::~PwgUtilityProcessHostClient() {
151   // Delete temp directory.
152   BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, files_.release());
153 }
154
155 void PwgUtilityProcessHostClient::Convert(
156     base::RefCountedMemory* data,
157     const PWGRasterConverter::ResultCallback& callback) {
158   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
159   callback_ = callback;
160   CHECK(!files_);
161   files_.reset(new FileHandlers());
162   BrowserThread::PostTaskAndReply(
163       BrowserThread::FILE, FROM_HERE,
164       base::Bind(&FileHandlers::Init, base::Unretained(files_.get()),
165                  make_scoped_refptr(data)),
166       base::Bind(&PwgUtilityProcessHostClient::OnFilesReadyOnUIThread, this));
167 }
168
169 void PwgUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
170   OnFailed();
171 }
172
173 bool PwgUtilityProcessHostClient::OnMessageReceived(
174   const IPC::Message& message) {
175   bool handled = true;
176   IPC_BEGIN_MESSAGE_MAP(PwgUtilityProcessHostClient, message)
177     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted)
178     IPC_MESSAGE_HANDLER(
179         ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded, OnSucceeded)
180     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed,
181                         OnFailed)
182     IPC_MESSAGE_UNHANDLED(handled = false)
183   IPC_END_MESSAGE_MAP()
184   return handled;
185 }
186
187 void PwgUtilityProcessHostClient::OnProcessStarted() {
188   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
189   if (!utility_process_host_) {
190     RunCallbackOnUIThread(false);
191     return;
192   }
193
194   base::ProcessHandle process = utility_process_host_->GetData().handle;
195   utility_process_host_->Send(new ChromeUtilityMsg_RenderPDFPagesToPWGRaster(
196       files_->GetPdfForProcess(process),
197       settings_,
198       bitmap_settings_,
199       files_->GetPwgForProcess(process)));
200   utility_process_host_.reset();
201 }
202
203 void PwgUtilityProcessHostClient::OnSucceeded() {
204   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
205   RunCallback(true);
206 }
207
208 void PwgUtilityProcessHostClient::OnFailed() {
209   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
210   RunCallback(false);
211 }
212
213 void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() {
214   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
215   if (!files_->IsValid()) {
216     RunCallbackOnUIThread(false);
217     return;
218   }
219   BrowserThread::PostTask(
220       BrowserThread::IO, FROM_HERE,
221       base::Bind(&PwgUtilityProcessHostClient::StartProcessOnIOThread, this));
222 }
223
224 void PwgUtilityProcessHostClient::StartProcessOnIOThread() {
225   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
226   utility_process_host_ =
227       content::UtilityProcessHost::Create(
228           this,
229           base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr();
230   utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
231 }
232
233 void PwgUtilityProcessHostClient::RunCallback(bool success) {
234   BrowserThread::PostTask(
235       BrowserThread::UI, FROM_HERE,
236       base::Bind(&PwgUtilityProcessHostClient::RunCallbackOnUIThread, this,
237                  success));
238 }
239
240 void PwgUtilityProcessHostClient::RunCallbackOnUIThread(bool success) {
241   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
242   if (!callback_.is_null()) {
243     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
244                             base::Bind(callback_, success,
245                                        files_->GetPwgPath()));
246     callback_.Reset();
247   }
248 }
249
250 class PWGRasterConverterImpl : public PWGRasterConverter {
251  public:
252   PWGRasterConverterImpl();
253
254   virtual ~PWGRasterConverterImpl();
255
256   virtual void Start(base::RefCountedMemory* data,
257                      const printing::PdfRenderSettings& conversion_settings,
258                      const printing::PwgRasterSettings& bitmap_settings,
259                      const ResultCallback& callback) OVERRIDE;
260
261  private:
262   scoped_refptr<PwgUtilityProcessHostClient> utility_client_;
263   base::CancelableCallback<ResultCallback::RunType> callback_;
264
265   DISALLOW_COPY_AND_ASSIGN(PWGRasterConverterImpl);
266 };
267
268 PWGRasterConverterImpl::PWGRasterConverterImpl() {
269 }
270
271 PWGRasterConverterImpl::~PWGRasterConverterImpl() {
272 }
273
274 void PWGRasterConverterImpl::Start(
275     base::RefCountedMemory* data,
276     const printing::PdfRenderSettings& conversion_settings,
277     const printing::PwgRasterSettings& bitmap_settings,
278     const ResultCallback& callback) {
279   // Rebind cancelable callback to avoid calling callback if
280   // PWGRasterConverterImpl is destroyed.
281   callback_.Reset(callback);
282   utility_client_ =
283       new PwgUtilityProcessHostClient(conversion_settings, bitmap_settings);
284   utility_client_->Convert(data, callback_.callback());
285 }
286
287 }  // namespace
288
289 // static
290 scoped_ptr<PWGRasterConverter> PWGRasterConverter::CreateDefault() {
291   return scoped_ptr<PWGRasterConverter>(new PWGRasterConverterImpl());
292 }
293
294 }  // namespace local_discovery