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