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/file.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"
22 namespace local_discovery
{
26 using content::BrowserThread
;
33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
36 void Init(base::RefCountedMemory
* data
);
39 base::FilePath
GetPwgPath() const {
40 return temp_dir_
.path().AppendASCII("output.pwg");
43 base::FilePath
GetPdfPath() const {
44 return temp_dir_
.path().AppendASCII("input.pdf");
47 IPC::PlatformFileForTransit
GetPdfForProcess(base::ProcessHandle process
) {
48 DCHECK(pdf_file_
.IsValid());
49 IPC::PlatformFileForTransit transit
=
50 IPC::TakeFileHandleForProcess(pdf_file_
.Pass(), process
);
54 IPC::PlatformFileForTransit
GetPwgForProcess(base::ProcessHandle process
) {
55 DCHECK(pwg_file_
.IsValid());
56 IPC::PlatformFileForTransit transit
=
57 IPC::TakeFileHandleForProcess(pwg_file_
.Pass(), process
);
62 base::ScopedTempDir temp_dir_
;
67 void FileHandlers::Init(base::RefCountedMemory
* data
) {
68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
70 if (!temp_dir_
.CreateUniqueTempDir()) {
74 if (static_cast<int>(data
->size()) !=
75 base::WriteFile(GetPdfPath(), data
->front_as
<char>(), data
->size())) {
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
);
86 bool FileHandlers::IsValid() {
87 return pdf_file_
.IsValid() && pwg_file_
.IsValid();
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
{
104 explicit PwgUtilityProcessHostClient(
105 const printing::PdfRenderSettings
& settings
,
106 const printing::PwgRasterSettings
& bitmap_settings
);
108 void Convert(base::RefCountedMemory
* data
,
109 const PWGRasterConverter::ResultCallback
& callback
);
111 // UtilityProcessHostClient implementation.
112 virtual void OnProcessCrashed(int exit_code
) OVERRIDE
;
113 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
;
116 virtual ~PwgUtilityProcessHostClient();
119 void OnProcessStarted();
123 void RunCallback(bool success
);
125 void StartProcessOnIOThread();
127 void RunCallbackOnUIThread(bool success
);
128 void OnFilesReadyOnUIThread();
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_
;
136 DISALLOW_COPY_AND_ASSIGN(PwgUtilityProcessHostClient
);
139 PwgUtilityProcessHostClient::PwgUtilityProcessHostClient(
140 const printing::PdfRenderSettings
& settings
,
141 const printing::PwgRasterSettings
& bitmap_settings
)
142 : settings_(settings
), bitmap_settings_(bitmap_settings
) {}
144 PwgUtilityProcessHostClient::~PwgUtilityProcessHostClient() {
147 void PwgUtilityProcessHostClient::Convert(
148 base::RefCountedMemory
* data
,
149 const PWGRasterConverter::ResultCallback
& callback
) {
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
151 callback_
= callback
;
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));
161 void PwgUtilityProcessHostClient::OnProcessCrashed(int exit_code
) {
165 bool PwgUtilityProcessHostClient::OnMessageReceived(
166 const IPC::Message
& message
) {
168 IPC_BEGIN_MESSAGE_MAP(PwgUtilityProcessHostClient
, message
)
169 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted
, OnProcessStarted
)
171 ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded
, OnSucceeded
)
172 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed
,
174 IPC_MESSAGE_UNHANDLED(handled
= false)
175 IPC_END_MESSAGE_MAP()
179 void PwgUtilityProcessHostClient::OnProcessStarted() {
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
181 if (!utility_process_host_
) {
182 RunCallbackOnUIThread(false);
186 base::ProcessHandle process
= utility_process_host_
->GetData().handle
;
187 utility_process_host_
->Send(new ChromeUtilityMsg_RenderPDFPagesToPWGRaster(
188 files_
->GetPdfForProcess(process
),
191 files_
->GetPwgForProcess(process
)));
192 utility_process_host_
.reset();
195 void PwgUtilityProcessHostClient::OnSucceeded() {
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
200 void PwgUtilityProcessHostClient::OnFailed() {
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
205 void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() {
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
207 if (!files_
->IsValid()) {
208 RunCallbackOnUIThread(false);
211 BrowserThread::PostTask(
212 BrowserThread::IO
, FROM_HERE
,
213 base::Bind(&PwgUtilityProcessHostClient::StartProcessOnIOThread
, this));
216 void PwgUtilityProcessHostClient::StartProcessOnIOThread() {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
218 utility_process_host_
=
219 content::UtilityProcessHost::Create(
221 base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr();
222 utility_process_host_
->Send(new ChromeUtilityMsg_StartupPing
);
225 void PwgUtilityProcessHostClient::RunCallback(bool success
) {
226 BrowserThread::PostTask(
227 BrowserThread::UI
, FROM_HERE
,
228 base::Bind(&PwgUtilityProcessHostClient::RunCallbackOnUIThread
, this,
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()));
242 class PWGRasterConverterImpl
: public PWGRasterConverter
{
244 PWGRasterConverterImpl();
246 virtual ~PWGRasterConverterImpl();
248 virtual void Start(base::RefCountedMemory
* data
,
249 const printing::PdfRenderSettings
& conversion_settings
,
250 const printing::PwgRasterSettings
& bitmap_settings
,
251 const ResultCallback
& callback
) OVERRIDE
;
254 scoped_refptr
<PwgUtilityProcessHostClient
> utility_client_
;
255 base::CancelableCallback
<ResultCallback::RunType
> callback_
;
257 DISALLOW_COPY_AND_ASSIGN(PWGRasterConverterImpl
);
260 PWGRasterConverterImpl::PWGRasterConverterImpl() {
263 PWGRasterConverterImpl::~PWGRasterConverterImpl() {
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
);
275 new PwgUtilityProcessHostClient(conversion_settings
, bitmap_settings
);
276 utility_client_
->Convert(data
, callback_
.callback());
282 scoped_ptr
<PWGRasterConverter
> PWGRasterConverter::CreateDefault() {
283 return scoped_ptr
<PWGRasterConverter
>(new PWGRasterConverterImpl());
286 } // namespace local_discovery