Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: chrome/browser/printing/pdf_to_emf_converter.cc

Issue 566693002: Use file handles to interact with utility process. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Wed Sep 17 10:40:51 PDT 2014 Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/printing/pdf_to_emf_converter.h ('k') | chrome/browser/printing/print_job.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/printing/pdf_to_emf_converter.h" 5 #include "chrome/browser/printing/pdf_to_emf_converter.h"
6 6
7 #include "base/bind_helpers.h" 7 #include <queue>
8 #include "base/cancelable_callback.h" 8
9 #include "base/files/file.h" 9 #include "base/files/file.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h" 11 #include "base/files/scoped_temp_dir.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "chrome/common/chrome_utility_messages.h" 13 #include "chrome/common/chrome_utility_messages.h"
14 #include "chrome/common/chrome_utility_printing_messages.h" 14 #include "chrome/common/chrome_utility_printing_messages.h"
15 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/child_process_data.h" 16 #include "content/public/browser/child_process_data.h"
17 #include "content/public/browser/utility_process_host.h" 17 #include "content/public/browser/utility_process_host.h"
18 #include "content/public/browser/utility_process_host_client.h" 18 #include "content/public/browser/utility_process_host_client.h"
19 #include "printing/emf_win.h" 19 #include "printing/emf_win.h"
20 #include "printing/page_range.h"
21 #include "printing/pdf_render_settings.h" 20 #include "printing/pdf_render_settings.h"
22 21
23 namespace printing { 22 namespace printing {
24 23
25 namespace { 24 namespace {
26 25
27 using content::BrowserThread; 26 using content::BrowserThread;
28 27
29 class FileHandlers 28 class PdfToEmfConverterImpl;
30 : public base::RefCountedThreadSafe<FileHandlers, 29
30 // Allows to delete temporary directory after all temporary files created inside
31 // are closed. Windows cannot delete directory with opened files. Directory is
32 // used to store PDF and metafiles. PDF should be gone by the time utility
33 // process exits. Metafiles should be gone when all LazyEmf destroyed.
34 class RefCountedTempDir
35 : public base::RefCountedThreadSafe<RefCountedTempDir,
31 BrowserThread::DeleteOnFileThread> { 36 BrowserThread::DeleteOnFileThread> {
32 public: 37 public:
33 FileHandlers() {} 38 RefCountedTempDir() { temp_dir_.CreateUniqueTempDir(); }
34 39 bool IsValid() const { return temp_dir_.IsValid(); }
35 void Init(base::RefCountedMemory* data); 40 const base::FilePath& GetPath() const { return temp_dir_.path(); }
36 bool IsValid();
37
38 base::FilePath GetEmfPath() const {
39 return temp_dir_.path().AppendASCII("output.emf");
40 }
41
42 base::FilePath GetEmfPagePath(int page_number) const {
43 return GetEmfPath().InsertBeforeExtensionASCII(
44 base::StringPrintf(".%d", page_number));
45 }
46
47 base::FilePath GetPdfPath() const {
48 return temp_dir_.path().AppendASCII("input.pdf");
49 }
50
51 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) {
52 DCHECK(pdf_file_.IsValid());
53 IPC::PlatformFileForTransit transit =
54 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process);
55 return transit;
56 }
57
58 const base::FilePath& GetBasePath() const {
59 return temp_dir_.path();
60 }
61 41
62 private: 42 private:
63 friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>; 43 friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
64 friend class base::DeleteHelper<FileHandlers>; 44 friend class base::DeleteHelper<RefCountedTempDir>;
65 45 ~RefCountedTempDir() {};
66 ~FileHandlers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); }
67 46
68 base::ScopedTempDir temp_dir_; 47 base::ScopedTempDir temp_dir_;
69 base::File pdf_file_; 48 DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir);
70 }; 49 };
71 50
72 void FileHandlers::Init(base::RefCountedMemory* data) { 51 typedef scoped_ptr<base::File, BrowserThread::DeleteOnFileThread>
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 52 ScopedTempFile;
74 53
75 if (!temp_dir_.CreateUniqueTempDir()) { 54 // Wrapper for Emf to keep only file handle in memory, and load actual data only
76 return; 55 // on playback. Emf::InitFromFile() can play metafile directly from disk, but it
77 } 56 // can't open file handles. We need file handles to reliably delete temporary
78 57 // files, and to efficiently interact with utility process.
79 pdf_file_.Initialize(GetPdfPath(), 58 class LazyEmf : public MetafilePlayer {
80 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
81 base::File::FLAG_READ |
82 base::File::FLAG_DELETE_ON_CLOSE);
83 if (static_cast<int>(data->size()) !=
84 pdf_file_.WriteAtCurrentPos(data->front_as<char>(), data->size())) {
85 pdf_file_.Close();
86 return;
87 }
88 pdf_file_.Seek(base::File::FROM_BEGIN, 0);
89 pdf_file_.Flush();
90 }
91
92 bool FileHandlers::IsValid() {
93 return pdf_file_.IsValid();
94 }
95
96 // Modification of Emf to keep references to |FileHandlers|.
97 // |FileHandlers| must be deleted after the last metafile is closed because
98 // Emf holds files locked.
99 // Ideally we want to use FLAG_DELETE_ON_CLOSE, but it requires large changes.
100 // It's going to be done for crbug.com/408184
101 class TempEmf : public Emf {
102 public: 59 public:
103 explicit TempEmf(const scoped_refptr<FileHandlers>& files) : files_(files) {} 60 LazyEmf(const scoped_refptr<RefCountedTempDir>& temp_dir, ScopedTempFile file)
104 virtual ~TempEmf() {} 61 : temp_dir_(temp_dir), file_(file.Pass()) {}
105 62 virtual ~LazyEmf() { Close(); }
106 virtual bool SafePlayback(HDC hdc) const OVERRIDE { 63
107 bool result = Emf::SafePlayback(hdc); 64 virtual bool SafePlayback(HDC hdc) const OVERRIDE;
108 TempEmf* this_mutable = const_cast<TempEmf*>(this); 65 virtual bool SaveTo(base::File* file) const OVERRIDE;
109 // TODO(vitalybuka): Fix destruction of metafiles. For some reasons
110 // instances of Emf are not deleted. crbug.com/411683
111 // |files_| must be released as soon as possible to guarantee deletion.
112 // It's know that this Emf file is going to be played just once to
113 // a printer. So just release files here.
114 this_mutable->Close();
115 this_mutable->files_ = NULL;
116 return result;
117 }
118 66
119 private: 67 private:
120 scoped_refptr<FileHandlers> files_; 68 void Close() const;
121 DISALLOW_COPY_AND_ASSIGN(TempEmf); 69 bool LoadEmf(Emf* emf) const;
70
71 mutable scoped_refptr<RefCountedTempDir> temp_dir_;
72 mutable ScopedTempFile file_; // Mutable because of consts in base class.
73
74 DISALLOW_COPY_AND_ASSIGN(LazyEmf);
122 }; 75 };
123 76
124 // Converts PDF into EMF. 77 // Converts PDF into EMF.
125 // Class uses 3 threads: UI, IO and FILE. 78 // Class uses 3 threads: UI, IO and FILE.
126 // Internal workflow is following: 79 // Internal workflow is following:
127 // 1. Create instance on the UI thread. (files_, settings_,) 80 // 1. Create instance on the UI thread. (files_, settings_,)
128 // 2. Create file on the FILE thread. 81 // 2. Create pdf file on the FILE thread.
129 // 3. Start utility process and start conversion on the IO thread. 82 // 3. Start utility process and start conversion on the IO thread.
130 // 4. Run result callback on the UI thread. 83 // 4. Utility process returns page count.
131 // 5. Instance is destroyed from any thread that has the last reference. 84 // 5. For each page:
132 // 6. FileHandlers destroyed on the FILE thread. 85 // 1. Clients requests page with file handle to a temp file.
133 // This step posts |FileHandlers| to be destroyed on the FILE thread. 86 // 2. Utility converts the page, save it to the file and reply.
87 //
134 // All these steps work sequentially, so no data should be accessed 88 // All these steps work sequentially, so no data should be accessed
135 // simultaneously by several threads. 89 // simultaneously by several threads.
136 class PdfToEmfUtilityProcessHostClient 90 class PdfToEmfUtilityProcessHostClient
137 : public content::UtilityProcessHostClient { 91 : public content::UtilityProcessHostClient {
138 public: 92 public:
139 explicit PdfToEmfUtilityProcessHostClient( 93 PdfToEmfUtilityProcessHostClient(
140 const printing::PdfRenderSettings& settings); 94 base::WeakPtr<PdfToEmfConverterImpl> converter,
141 95 const PdfRenderSettings& settings);
142 void Convert(base::RefCountedMemory* data, 96
143 const PdfToEmfConverter::ResultCallback& callback); 97 void Start(const scoped_refptr<base::RefCountedMemory>& data,
98 const PdfToEmfConverter::StartCallback& start_callback);
99
100 void GetPage(int page_number,
101 const PdfToEmfConverter::GetPageCallback& get_page_callback);
102
103 void Stop();
144 104
145 // UtilityProcessHostClient implementation. 105 // UtilityProcessHostClient implementation.
146 virtual void OnProcessCrashed(int exit_code) OVERRIDE; 106 virtual void OnProcessCrashed(int exit_code) OVERRIDE;
107 virtual void OnProcessLaunchFailed() OVERRIDE;
147 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 108 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
148 109
149 private: 110 private:
111 class GetPageCallbackData {
112 MOVE_ONLY_TYPE_FOR_CPP_03(GetPageCallbackData, RValue);
113
114 public:
115 GetPageCallbackData(int page_number,
116 PdfToEmfConverter::GetPageCallback callback)
117 : page_number_(page_number), callback_(callback) {}
118
119 // Move constructor for STL.
120 GetPageCallbackData(RValue other) { this->operator=(other); }
121
122 // Move assignment for STL.
123 GetPageCallbackData& operator=(RValue rhs) {
124 page_number_ = rhs.object->page_number_;
125 callback_ = rhs.object->callback_;
126 emf_ = rhs.object->emf_.Pass();
127 return *this;
128 }
129
130 int page_number() const { return page_number_; }
131 const PdfToEmfConverter::GetPageCallback& callback() const {
132 return callback_;
133 }
134 ScopedTempFile emf() { return emf_.Pass(); }
135 void set_emf(ScopedTempFile emf) { emf_ = emf.Pass(); }
136
137 private:
138 int page_number_;
139 PdfToEmfConverter::GetPageCallback callback_;
140 ScopedTempFile emf_;
141 };
142
150 virtual ~PdfToEmfUtilityProcessHostClient(); 143 virtual ~PdfToEmfUtilityProcessHostClient();
151 144
145 bool Send(IPC::Message* msg);
146
152 // Message handlers. 147 // Message handlers.
153 void OnProcessStarted(); 148 void OnProcessStarted();
154 void OnSucceeded(const std::vector<printing::PageRange>& page_ranges, 149 void OnPageCount(int page_count);
155 double scale_factor); 150 void OnPageDone(bool success, double scale_factor);
151
156 void OnFailed(); 152 void OnFailed();
157 153 void OnTempPdfReady(ScopedTempFile pdf);
158 void RunCallback(const std::vector<printing::PageRange>& page_ranges, 154 void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf);
159 double scale_factor); 155
160 156 scoped_refptr<RefCountedTempDir> temp_dir_;
161 void StartProcessOnIOThread(); 157
162 158 // Used to suppress callbacks after PdfToEmfConverterImpl is deleted.
163 void RunCallbackOnUIThread( 159 base::WeakPtr<PdfToEmfConverterImpl> converter_;
164 const std::vector<printing::PageRange>& page_ranges, 160 PdfRenderSettings settings_;
165 double scale_factor); 161 scoped_refptr<base::RefCountedMemory> data_;
166 void OnFilesReadyOnUIThread(); 162
167 163 // Document loaded callback.
168 scoped_refptr<FileHandlers> files_; 164 PdfToEmfConverter::StartCallback start_callback_;
169 printing::PdfRenderSettings settings_; 165
170 PdfToEmfConverter::ResultCallback callback_; 166 // Process host for IPC.
171 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; 167 base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
172 168
169 // Queue of callbacks for GetPage() requests. Utility process should reply
170 // with PageDone in the same order as requests were received.
171 // Use containers that keeps element pointers valid after push() and pop().
172 typedef std::queue<GetPageCallbackData> GetPageCallbacks;
173 GetPageCallbacks get_page_callbacks_;
174
173 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); 175 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient);
174 }; 176 };
175 177
178 class PdfToEmfConverterImpl : public PdfToEmfConverter {
179 public:
180 PdfToEmfConverterImpl();
181
182 virtual ~PdfToEmfConverterImpl();
183
184 virtual void Start(const scoped_refptr<base::RefCountedMemory>& data,
185 const PdfRenderSettings& conversion_settings,
186 const StartCallback& start_callback) OVERRIDE;
187
188 virtual void GetPage(int page_number,
189 const GetPageCallback& get_page_callback) OVERRIDE;
190
191 // Helps to cancel callbacks if this object is destroyed.
192 void RunCallback(const base::Closure& callback);
193
194 private:
195 scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_;
196 base::WeakPtrFactory<PdfToEmfConverterImpl> weak_ptr_factory_;
197
198 DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl);
199 };
200
201 ScopedTempFile CreateTempFile(scoped_refptr<RefCountedTempDir>* temp_dir) {
202 if (!(*temp_dir))
203 *temp_dir = new RefCountedTempDir();
204 ScopedTempFile file;
205 if (!(*temp_dir)->IsValid())
206 return file.Pass();
207 base::FilePath path;
208 if (!base::CreateTemporaryFileInDir((*temp_dir)->GetPath(), &path))
209 return file.Pass();
210 file.reset(new base::File(path,
211 base::File::FLAG_CREATE_ALWAYS |
212 base::File::FLAG_WRITE |
213 base::File::FLAG_READ |
214 base::File::FLAG_DELETE_ON_CLOSE |
215 base::File::FLAG_TEMPORARY));
216 if (!file->IsValid())
217 file.reset();
218 return file.Pass();
219 }
220
221 ScopedTempFile CreateTempPdfFile(
222 const scoped_refptr<base::RefCountedMemory>& data,
223 scoped_refptr<RefCountedTempDir>* temp_dir) {
224 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
225
226 ScopedTempFile pdf_file = CreateTempFile(temp_dir);
227 if (!pdf_file ||
228 static_cast<int>(data->size()) !=
229 pdf_file->WriteAtCurrentPos(data->front_as<char>(), data->size())) {
230 pdf_file.reset();
231 }
232 pdf_file->Seek(base::File::FROM_BEGIN, 0);
233 return pdf_file.Pass();
234 }
235
236 bool LazyEmf::SafePlayback(HDC hdc) const {
237 Emf emf;
238 bool result = LoadEmf(&emf) && emf.SafePlayback(hdc);
239 // TODO(vitalybuka): Fix destruction of metafiles. For some reasons
240 // instances of Emf are not deleted. crbug.com/411683
241 // It's known that the Emf going to be played just once to a printer. So just
242 // release file here.
243 Close();
244 return result;
245 }
246
247 bool LazyEmf::SaveTo(base::File* file) const {
248 Emf emf;
249 return LoadEmf(&emf) && emf.SaveTo(file);
250 }
251
252 void LazyEmf::Close() const {
253 file_.reset();
254 temp_dir_ = NULL;
255 }
256
257 bool LazyEmf::LoadEmf(Emf* emf) const {
258 file_->Seek(base::File::FROM_BEGIN, 0);
259 int64 size = file_->GetLength();
260 if (size <= 0)
261 return false;
262 std::vector<char> data(size);
263 if (file_->ReadAtCurrentPos(data.data(), data.size()) != size)
264 return false;
265 return emf->InitFromData(data.data(), data.size());
266 }
267
176 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( 268 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
177 const printing::PdfRenderSettings& settings) 269 base::WeakPtr<PdfToEmfConverterImpl> converter,
178 : settings_(settings) {} 270 const PdfRenderSettings& settings)
271 : converter_(converter), settings_(settings) {
272 }
179 273
180 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { 274 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
181 } 275 }
182 276
183 void PdfToEmfUtilityProcessHostClient::Convert( 277 void PdfToEmfUtilityProcessHostClient::Start(
184 base::RefCountedMemory* data, 278 const scoped_refptr<base::RefCountedMemory>& data,
185 const PdfToEmfConverter::ResultCallback& callback) { 279 const PdfToEmfConverter::StartCallback& start_callback) {
186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 280 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
187 callback_ = callback; 281 BrowserThread::PostTask(BrowserThread::IO,
188 CHECK(!files_.get()); 282 FROM_HERE,
189 files_ = new FileHandlers(); 283 base::Bind(&PdfToEmfUtilityProcessHostClient::Start,
190 BrowserThread::PostTaskAndReply( 284 this,
285 data,
286 start_callback));
287 return;
288 }
289 data_ = data;
290
291 // Store callback before any OnFailed() call to make it called on failure.
292 start_callback_ = start_callback;
293
294 // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load
295 // gdiplus.dll, change how rendering happens, and not be able to correctly
296 // generate when sent to a metafile DC.
297 utility_process_host_ =
298 content::UtilityProcessHost::Create(
299 this, base::MessageLoop::current()->message_loop_proxy())
300 ->AsWeakPtr();
301 if (!utility_process_host_)
302 return OnFailed();
303 // Should reply with OnProcessStarted().
304 Send(new ChromeUtilityMsg_StartupPing);
305 }
306
307 void PdfToEmfUtilityProcessHostClient::OnProcessStarted() {
308 DCHECK_CURRENTLY_ON(BrowserThread::IO);
309 if (!utility_process_host_)
310 return OnFailed();
311
312 base::ProcessHandle process = utility_process_host_->GetData().handle;
313 scoped_refptr<base::RefCountedMemory> data = data_;
314 data_ = NULL;
315 BrowserThread::PostTaskAndReplyWithResult(
191 BrowserThread::FILE, 316 BrowserThread::FILE,
192 FROM_HERE, 317 FROM_HERE,
193 base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)), 318 base::Bind(&CreateTempPdfFile, data, &temp_dir_),
194 base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread, 319 base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this));
195 this)); 320 }
321
322 void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) {
323 DCHECK_CURRENTLY_ON(BrowserThread::IO);
324 if (!utility_process_host_)
325 return OnFailed();
326 base::ProcessHandle process = utility_process_host_->GetData().handle;
327 // Should reply with OnPageCount().
328 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(
329 IPC::GetFileHandleForProcess(pdf->GetPlatformFile(), process, false),
330 settings_));
331 }
332
333 void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) {
334 DCHECK_CURRENTLY_ON(BrowserThread::IO);
335 if (start_callback_.is_null())
336 return OnFailed();
337 BrowserThread::PostTask(BrowserThread::UI,
338 FROM_HERE,
339 base::Bind(&PdfToEmfConverterImpl::RunCallback,
340 converter_,
341 base::Bind(start_callback_, page_count)));
342 start_callback_.Reset();
343 }
344
345 void PdfToEmfUtilityProcessHostClient::GetPage(
346 int page_number,
347 const PdfToEmfConverter::GetPageCallback& get_page_callback) {
348 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
349 BrowserThread::PostTask(
350 BrowserThread::IO,
351 FROM_HERE,
352 base::Bind(&PdfToEmfUtilityProcessHostClient::GetPage,
353 this,
354 page_number,
355 get_page_callback));
356 return;
357 }
358
359 // Store callback before any OnFailed() call to make it called on failure.
360 get_page_callbacks_.push(GetPageCallbackData(page_number, get_page_callback));
361
362 if (!utility_process_host_)
363 return OnFailed();
364
365 BrowserThread::PostTaskAndReplyWithResult(
366 BrowserThread::FILE,
367 FROM_HERE,
368 base::Bind(&CreateTempFile, &temp_dir_),
369 base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempEmfReady,
370 this,
371 &get_page_callbacks_.back()));
372 }
373
374 void PdfToEmfUtilityProcessHostClient::OnTempEmfReady(
375 GetPageCallbackData* callback_data,
376 ScopedTempFile emf) {
377 DCHECK_CURRENTLY_ON(BrowserThread::IO);
378 if (!utility_process_host_)
379 return OnFailed();
380 base::ProcessHandle process = utility_process_host_->GetData().handle;
381 IPC::PlatformFileForTransit transit =
382 IPC::GetFileHandleForProcess(emf->GetPlatformFile(), process, false);
383 callback_data->set_emf(emf.Pass());
384 // Should reply with OnPageDone().
385 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage(
386 callback_data->page_number(), transit));
387 }
388
389 void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success,
390 double scale_factor) {
391 DCHECK_CURRENTLY_ON(BrowserThread::IO);
392 if (get_page_callbacks_.empty())
393 return OnFailed();
394 scoped_ptr<LazyEmf> emf;
395 GetPageCallbackData& data = get_page_callbacks_.front();
396 if (success)
397 emf.reset(new LazyEmf(temp_dir_, data.emf().Pass()));
398 BrowserThread::PostTask(BrowserThread::UI,
399 FROM_HERE,
400 base::Bind(&PdfToEmfConverterImpl::RunCallback,
401 converter_,
402 base::Bind(data.callback(),
403 data.page_number(),
404 scale_factor,
405 base::Passed(&emf))));
406 get_page_callbacks_.pop();
407 }
408
409 void PdfToEmfUtilityProcessHostClient::Stop() {
410 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
411 BrowserThread::PostTask(
412 BrowserThread::IO,
413 FROM_HERE,
414 base::Bind(&PdfToEmfUtilityProcessHostClient::Stop, this));
415 return;
416 }
417 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop());
196 } 418 }
197 419
198 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { 420 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
199 OnFailed(); 421 OnFailed();
200 } 422 }
201 423
424 void PdfToEmfUtilityProcessHostClient::OnProcessLaunchFailed() {
425 OnFailed();
426 }
427
202 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( 428 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived(
203 const IPC::Message& message) { 429 const IPC::Message& message) {
204 bool handled = true; 430 bool handled = true;
205 IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message) 431 IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message)
206 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) 432 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted)
207 IPC_MESSAGE_HANDLER( 433 IPC_MESSAGE_HANDLER(
208 ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_Succeeded, OnSucceeded) 434 ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount)
209 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed, 435 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone,
210 OnFailed) 436 OnPageDone)
211 IPC_MESSAGE_UNHANDLED(handled = false) 437 IPC_MESSAGE_UNHANDLED(handled = false)
212 IPC_END_MESSAGE_MAP() 438 IPC_END_MESSAGE_MAP()
213 return handled; 439 return handled;
214 } 440 }
215 441
216 void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { 442 bool PdfToEmfUtilityProcessHostClient::Send(IPC::Message* msg) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 443 if (utility_process_host_)
218 if (!utility_process_host_) { 444 return utility_process_host_->Send(msg);
219 RunCallbackOnUIThread(std::vector<printing::PageRange>(), 0.0); 445 delete msg;
220 return; 446 return false;
221 } 447 }
222 448
223 base::ProcessHandle process = utility_process_host_->GetData().handle; 449 void PdfToEmfUtilityProcessHostClient::OnFailed() {
224 utility_process_host_->Send( 450 DCHECK_CURRENTLY_ON(BrowserThread::IO);
225 new ChromeUtilityMsg_RenderPDFPagesToMetafiles( 451 if (!start_callback_.is_null())
226 files_->GetPdfForProcess(process), 452 OnPageCount(0);
227 files_->GetEmfPath(), 453 while (!get_page_callbacks_.empty())
228 settings_, 454 OnPageDone(false, 0.0);
229 std::vector<printing::PageRange>()));
230 utility_process_host_.reset(); 455 utility_process_host_.reset();
231 } 456 }
232 457
233 void PdfToEmfUtilityProcessHostClient::OnSucceeded( 458 PdfToEmfConverterImpl::PdfToEmfConverterImpl() : weak_ptr_factory_(this) {
234 const std::vector<printing::PageRange>& page_ranges,
235 double scale_factor) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
237 RunCallback(page_ranges, scale_factor);
238 }
239
240 void PdfToEmfUtilityProcessHostClient::OnFailed() {
241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
242 RunCallback(std::vector<printing::PageRange>(), 0.0);
243 }
244
245 void PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread() {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
247 if (!files_->IsValid()) {
248 RunCallbackOnUIThread(std::vector<printing::PageRange>(), 0.0);
249 return;
250 }
251 BrowserThread::PostTask(
252 BrowserThread::IO,
253 FROM_HERE,
254 base::Bind(&PdfToEmfUtilityProcessHostClient::StartProcessOnIOThread,
255 this));
256 }
257
258 void PdfToEmfUtilityProcessHostClient::StartProcessOnIOThread() {
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
260 utility_process_host_ =
261 content::UtilityProcessHost::Create(
262 this,
263 base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr();
264 // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load
265 // gdiplus.dll, change how rendering happens, and not be able to correctly
266 // generate when sent to a metafile DC.
267 utility_process_host_->SetExposedDir(files_->GetBasePath());
268 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
269 }
270
271 void PdfToEmfUtilityProcessHostClient::RunCallback(
272 const std::vector<printing::PageRange>& page_ranges,
273 double scale_factor) {
274 BrowserThread::PostTask(
275 BrowserThread::UI,
276 FROM_HERE,
277 base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread,
278 this,
279 page_ranges,
280 scale_factor));
281 }
282
283 void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread(
284 const std::vector<printing::PageRange>& page_ranges,
285 double scale_factor) {
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
287 ScopedVector<MetafilePlayer> pages;
288 std::vector<printing::PageRange>::const_iterator iter;
289 for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) {
290 for (int page_number = iter->from; page_number <= iter->to; ++page_number) {
291 scoped_ptr<TempEmf> metafile(new TempEmf(files_));
292 if (!metafile->InitFromFile(files_->GetEmfPagePath(page_number))) {
293 NOTREACHED() << "Invalid metafile";
294 metafile.reset();
295 }
296 pages.push_back(metafile.release());
297 }
298 }
299 files_ = NULL;
300 if (!callback_.is_null()) {
301 callback_.Run(scale_factor, &pages);
302 callback_.Reset();
303 }
304 }
305
306 class PdfToEmfConverterImpl : public PdfToEmfConverter {
307 public:
308 PdfToEmfConverterImpl();
309
310 virtual ~PdfToEmfConverterImpl();
311
312 virtual void Start(base::RefCountedMemory* data,
313 const printing::PdfRenderSettings& conversion_settings,
314 const ResultCallback& callback) OVERRIDE;
315
316 private:
317 scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_;
318 base::CancelableCallback<ResultCallback::RunType> callback_;
319
320 DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl);
321 };
322
323 PdfToEmfConverterImpl::PdfToEmfConverterImpl() {
324 } 459 }
325 460
326 PdfToEmfConverterImpl::~PdfToEmfConverterImpl() { 461 PdfToEmfConverterImpl::~PdfToEmfConverterImpl() {
462 if (utility_client_)
463 utility_client_->Stop();
327 } 464 }
328 465
329 void PdfToEmfConverterImpl::Start( 466 void PdfToEmfConverterImpl::Start(
330 base::RefCountedMemory* data, 467 const scoped_refptr<base::RefCountedMemory>& data,
331 const printing::PdfRenderSettings& conversion_settings, 468 const PdfRenderSettings& conversion_settings,
332 const ResultCallback& callback) { 469 const StartCallback& start_callback) {
333 // Rebind cancelable callback to avoid calling callback if 470 DCHECK(!utility_client_);
334 // PdfToEmfConverterImpl is destroyed. 471 utility_client_ = new PdfToEmfUtilityProcessHostClient(
335 callback_.Reset(callback); 472 weak_ptr_factory_.GetWeakPtr(), conversion_settings);
336 utility_client_ = new PdfToEmfUtilityProcessHostClient(conversion_settings); 473 utility_client_->Start(data, start_callback);
337 utility_client_->Convert(data, callback_.callback()); 474 }
475
476 void PdfToEmfConverterImpl::GetPage(int page_number,
477 const GetPageCallback& get_page_callback) {
478 utility_client_->GetPage(page_number, get_page_callback);
479 }
480
481 void PdfToEmfConverterImpl::RunCallback(const base::Closure& callback) {
482 DCHECK_CURRENTLY_ON(BrowserThread::UI);
483 callback.Run();
338 } 484 }
339 485
340 } // namespace 486 } // namespace
341 487
488 PdfToEmfConverter::~PdfToEmfConverter() {
489 }
490
342 // static 491 // static
343 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { 492 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() {
344 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); 493 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl());
345 } 494 }
346 495
347 } // namespace printing 496 } // namespace printing
OLDNEW
« no previous file with comments | « chrome/browser/printing/pdf_to_emf_converter.h ('k') | chrome/browser/printing/print_job.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698