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

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

Issue 2633573002: Add Postscript Printing (Closed)
Patch Set: Fix Linux compile error Created 3 years, 11 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
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 <stdint.h> 7 #include <stdint.h>
8 #include <windows.h> 8 #include <windows.h>
9 9
10 #include <memory> 10 #include <memory>
(...skipping 12 matching lines...) Expand all
23 #include "chrome/common/chrome_utility_printing_messages.h" 23 #include "chrome/common/chrome_utility_printing_messages.h"
24 #include "chrome/grit/generated_resources.h" 24 #include "chrome/grit/generated_resources.h"
25 #include "content/public/browser/browser_thread.h" 25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/child_process_data.h" 26 #include "content/public/browser/child_process_data.h"
27 #include "content/public/browser/utility_process_host.h" 27 #include "content/public/browser/utility_process_host.h"
28 #include "content/public/browser/utility_process_host_client.h" 28 #include "content/public/browser/utility_process_host_client.h"
29 #include "printing/emf_win.h" 29 #include "printing/emf_win.h"
30 #include "printing/pdf_render_settings.h" 30 #include "printing/pdf_render_settings.h"
31 #include "ui/base/l10n/l10n_util.h" 31 #include "ui/base/l10n/l10n_util.h"
32 32
33 using content::BrowserThread;
34
33 namespace printing { 35 namespace printing {
34 36
35 namespace { 37 namespace {
36 38
37 using content::BrowserThread;
38
39 class PdfToEmfConverterImpl; 39 class PdfToEmfConverterImpl;
40 40
41 // Allows to delete temporary directory after all temporary files created inside 41 // Allows to delete temporary directory after all temporary files created inside
42 // are closed. Windows cannot delete directory with opened files. Directory is 42 // are closed. Windows cannot delete directory with opened files. Directory is
43 // used to store PDF and metafiles. PDF should be gone by the time utility 43 // used to store PDF and metafiles. PDF should be gone by the time utility
44 // process exits. Metafiles should be gone when all LazyEmf destroyed. 44 // process exits. Metafiles should be gone when all LazyEmf destroyed.
45 class RefCountedTempDir 45 class RefCountedTempDir
46 : public base::RefCountedThreadSafe<RefCountedTempDir, 46 : public base::RefCountedThreadSafe<RefCountedTempDir,
47 BrowserThread::DeleteOnFileThread> { 47 BrowserThread::DeleteOnFileThread> {
48 public: 48 public:
49 RefCountedTempDir() { ignore_result(temp_dir_.CreateUniqueTempDir()); } 49 RefCountedTempDir() { ignore_result(temp_dir_.CreateUniqueTempDir()); }
50 bool IsValid() const { return temp_dir_.IsValid(); } 50 bool IsValid() const { return temp_dir_.IsValid(); }
51 const base::FilePath& GetPath() const { return temp_dir_.GetPath(); } 51 const base::FilePath& GetPath() const { return temp_dir_.GetPath(); }
52 52
53 private: 53 private:
54 friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>; 54 friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
55 friend class base::DeleteHelper<RefCountedTempDir>; 55 friend class base::DeleteHelper<RefCountedTempDir>;
56 ~RefCountedTempDir() {} 56 ~RefCountedTempDir() {}
57 57
58 base::ScopedTempDir temp_dir_; 58 base::ScopedTempDir temp_dir_;
59 DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir); 59 DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir);
60 }; 60 };
61 61
62 typedef std::unique_ptr<base::File, BrowserThread::DeleteOnFileThread> 62 using ScopedTempFile =
63 ScopedTempFile; 63 std::unique_ptr<base::File, BrowserThread::DeleteOnFileThread>;
64 64
65 // Wrapper for Emf to keep only file handle in memory, and load actual data only 65 // Wrapper for Emf to keep only file handle in memory, and load actual data only
66 // on playback. Emf::InitFromFile() can play metafile directly from disk, but it 66 // on playback. Emf::InitFromFile() can play metafile directly from disk, but it
67 // can't open file handles. We need file handles to reliably delete temporary 67 // can't open file handles. We need file handles to reliably delete temporary
68 // files, and to efficiently interact with utility process. 68 // files, and to efficiently interact with utility process.
69 class LazyEmf : public MetafilePlayer { 69 class LazyEmf : public MetafilePlayer {
70 public: 70 public:
71 LazyEmf(const scoped_refptr<RefCountedTempDir>& temp_dir, ScopedTempFile file) 71 LazyEmf(const scoped_refptr<RefCountedTempDir>& temp_dir, ScopedTempFile file)
72 : temp_dir_(temp_dir), file_(std::move(file)) { 72 : temp_dir_(temp_dir), file_(std::move(file)) {
73 CHECK(file_); 73 CHECK(file_);
74 } 74 }
75 ~LazyEmf() override { Close(); } 75 ~LazyEmf() override { Close(); }
76 76
77 private:
78 // MetafilePlayer:
77 bool SafePlayback(HDC hdc) const override; 79 bool SafePlayback(HDC hdc) const override;
78 bool GetDataAsVector(std::vector<char>* buffer) const override; 80 bool GetDataAsVector(std::vector<char>* buffer) const override;
79 bool SaveTo(base::File* file) const override; 81 bool SaveTo(base::File* file) const override;
80 82
81 private:
82 void Close() const; 83 void Close() const;
83 bool LoadEmf(Emf* emf) const; 84 bool LoadEmf(Emf* emf) const;
84 85
85 mutable scoped_refptr<RefCountedTempDir> temp_dir_; 86 mutable scoped_refptr<RefCountedTempDir> temp_dir_;
86 mutable ScopedTempFile file_; // Mutable because of consts in base class. 87 mutable ScopedTempFile file_; // Mutable because of consts in base class.
87 88
88 DISALLOW_COPY_AND_ASSIGN(LazyEmf); 89 DISALLOW_COPY_AND_ASSIGN(LazyEmf);
89 }; 90 };
90 91
91 // Converts PDF into EMF. 92 // Converts PDF into EMF.
(...skipping 10 matching lines...) Expand all
102 // All these steps work sequentially, so no data should be accessed 103 // All these steps work sequentially, so no data should be accessed
103 // simultaneously by several threads. 104 // simultaneously by several threads.
104 class PdfToEmfUtilityProcessHostClient 105 class PdfToEmfUtilityProcessHostClient
105 : public content::UtilityProcessHostClient { 106 : public content::UtilityProcessHostClient {
106 public: 107 public:
107 PdfToEmfUtilityProcessHostClient( 108 PdfToEmfUtilityProcessHostClient(
108 base::WeakPtr<PdfToEmfConverterImpl> converter, 109 base::WeakPtr<PdfToEmfConverterImpl> converter,
109 const PdfRenderSettings& settings); 110 const PdfRenderSettings& settings);
110 111
111 void Start(const scoped_refptr<base::RefCountedMemory>& data, 112 void Start(const scoped_refptr<base::RefCountedMemory>& data,
112 bool print_text_with_gdi,
113 const PdfToEmfConverter::StartCallback& start_callback); 113 const PdfToEmfConverter::StartCallback& start_callback);
114 114
115 void GetPage(int page_number, 115 void GetPage(int page_number,
116 const PdfToEmfConverter::GetPageCallback& get_page_callback); 116 const PdfToEmfConverter::GetPageCallback& get_page_callback);
117 117
118 void Stop(); 118 void Stop();
119 119
120 // Needs to be public to handle ChromeUtilityHostMsg_PreCacheFontCharacters 120 // Needs to be public to handle ChromeUtilityHostMsg_PreCacheFontCharacters
121 // sync message replies. 121 // sync message replies.
122 bool Send(IPC::Message* msg); 122 bool Send(IPC::Message* msg);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 161
162 ~PdfToEmfUtilityProcessHostClient() override; 162 ~PdfToEmfUtilityProcessHostClient() override;
163 163
164 // Message handlers. 164 // Message handlers.
165 void OnPageCount(int page_count); 165 void OnPageCount(int page_count);
166 void OnPageDone(bool success, float scale_factor); 166 void OnPageDone(bool success, float scale_factor);
167 void OnPreCacheFontCharacters(const LOGFONT& log_font, 167 void OnPreCacheFontCharacters(const LOGFONT& log_font,
168 const base::string16& characters); 168 const base::string16& characters);
169 169
170 void OnFailed(); 170 void OnFailed();
171 void OnTempPdfReady(bool print_text_with_gdi, ScopedTempFile pdf); 171 void OnTempPdfReady(ScopedTempFile pdf);
172 void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf); 172 void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf);
173 173
174 scoped_refptr<RefCountedTempDir> temp_dir_; 174 scoped_refptr<RefCountedTempDir> temp_dir_;
175 175
176 // Used to suppress callbacks after PdfToEmfConverterImpl is deleted. 176 // Used to suppress callbacks after PdfToEmfConverterImpl is deleted.
177 base::WeakPtr<PdfToEmfConverterImpl> converter_; 177 base::WeakPtr<PdfToEmfConverterImpl> converter_;
178 PdfRenderSettings settings_; 178 PdfRenderSettings settings_;
179 179
180 // Document loaded callback. 180 // Document loaded callback.
181 PdfToEmfConverter::StartCallback start_callback_; 181 PdfToEmfConverter::StartCallback start_callback_;
182 182
183 // Process host for IPC. 183 // Process host for IPC.
184 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; 184 base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
185 185
186 // Queue of callbacks for GetPage() requests. Utility process should reply 186 // Queue of callbacks for GetPage() requests. Utility process should reply
187 // with PageDone in the same order as requests were received. 187 // with PageDone in the same order as requests were received.
188 // Use containers that keeps element pointers valid after push() and pop(). 188 // Use containers that keeps element pointers valid after push() and pop().
189 typedef std::queue<GetPageCallbackData> GetPageCallbacks; 189 using GetPageCallbacks = std::queue<GetPageCallbackData>;
190 GetPageCallbacks get_page_callbacks_; 190 GetPageCallbacks get_page_callbacks_;
191 191
192 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); 192 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient);
193 }; 193 };
194 194
195 class PdfToEmfConverterImpl : public PdfToEmfConverter { 195 class PdfToEmfConverterImpl : public PdfToEmfConverter {
196 public: 196 public:
197 PdfToEmfConverterImpl(); 197 PdfToEmfConverterImpl();
198 198
199 ~PdfToEmfConverterImpl() override; 199 ~PdfToEmfConverterImpl() override;
200 200
201 void Start(const scoped_refptr<base::RefCountedMemory>& data, 201 void Start(const scoped_refptr<base::RefCountedMemory>& data,
202 const PdfRenderSettings& conversion_settings, 202 const PdfRenderSettings& conversion_settings,
203 bool print_text_with_gdi,
204 const StartCallback& start_callback) override; 203 const StartCallback& start_callback) override;
205 204
206 void GetPage(int page_number, 205 void GetPage(int page_number,
207 const GetPageCallback& get_page_callback) override; 206 const GetPageCallback& get_page_callback) override;
208 207
209 // Helps to cancel callbacks if this object is destroyed. 208 // Helps to cancel callbacks if this object is destroyed.
210 void RunCallback(const base::Closure& callback); 209 void RunCallback(const base::Closure& callback);
211 210
212 private: 211 private:
213 scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_; 212 scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 pdf_file.reset(); 252 pdf_file.reset();
254 return pdf_file; 253 return pdf_file;
255 } 254 }
256 pdf_file->Seek(base::File::FROM_BEGIN, 0); 255 pdf_file->Seek(base::File::FROM_BEGIN, 0);
257 return pdf_file; 256 return pdf_file;
258 } 257 }
259 258
260 bool LazyEmf::SafePlayback(HDC hdc) const { 259 bool LazyEmf::SafePlayback(HDC hdc) const {
261 Emf emf; 260 Emf emf;
262 bool result = LoadEmf(&emf) && emf.SafePlayback(hdc); 261 bool result = LoadEmf(&emf) && emf.SafePlayback(hdc);
263 // TODO(vitalybuka): Fix destruction of metafiles. For some reasons 262 // TODO(thestig): Fix destruction of metafiles. For some reasons
264 // instances of Emf are not deleted. crbug.com/411683 263 // instances of Emf are not deleted. https://crbug.com/260806
265 // It's known that the Emf going to be played just once to a printer. So just 264 // It's known that the Emf going to be played just once to a printer. So just
266 // release file here. 265 // release |file_| here.
267 Close(); 266 Close();
268 return result; 267 return result;
269 } 268 }
270 269
271 bool LazyEmf::GetDataAsVector(std::vector<char>* buffer) const { 270 bool LazyEmf::GetDataAsVector(std::vector<char>* buffer) const {
272 NOTREACHED(); 271 NOTREACHED();
273 return false; 272 return false;
274 } 273 }
275 274
276 bool LazyEmf::SaveTo(base::File* file) const { 275 bool LazyEmf::SaveTo(base::File* file) const {
277 Emf emf; 276 Emf emf;
278 return LoadEmf(&emf) && emf.SaveTo(file); 277 return LoadEmf(&emf) && emf.SaveTo(file);
279 } 278 }
280 279
281 void LazyEmf::Close() const { 280 void LazyEmf::Close() const {
282 file_.reset(); 281 file_.reset();
283 temp_dir_ = NULL; 282 temp_dir_ = nullptr;
284 } 283 }
285 284
286 bool LazyEmf::LoadEmf(Emf* emf) const { 285 bool LazyEmf::LoadEmf(Emf* emf) const {
287 file_->Seek(base::File::FROM_BEGIN, 0); 286 file_->Seek(base::File::FROM_BEGIN, 0);
288 int64_t size = file_->GetLength(); 287 int64_t size = file_->GetLength();
289 if (size <= 0) 288 if (size <= 0)
290 return false; 289 return false;
291 std::vector<char> data(size); 290 std::vector<char> data(size);
292 if (file_->ReadAtCurrentPos(data.data(), data.size()) != size) 291 if (file_->ReadAtCurrentPos(data.data(), data.size()) != size)
293 return false; 292 return false;
294 return emf->InitFromData(data.data(), data.size()); 293 return emf->InitFromData(data.data(), data.size());
295 } 294 }
296 295
297 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( 296 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
298 base::WeakPtr<PdfToEmfConverterImpl> converter, 297 base::WeakPtr<PdfToEmfConverterImpl> converter,
299 const PdfRenderSettings& settings) 298 const PdfRenderSettings& settings)
300 : converter_(converter), settings_(settings) { 299 : converter_(converter), settings_(settings) {
301 } 300 }
302 301
303 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { 302 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
304 } 303 }
305 304
306 void PdfToEmfUtilityProcessHostClient::Start( 305 void PdfToEmfUtilityProcessHostClient::Start(
307 const scoped_refptr<base::RefCountedMemory>& data, 306 const scoped_refptr<base::RefCountedMemory>& data,
308 bool print_text_with_gdi,
309 const PdfToEmfConverter::StartCallback& start_callback) { 307 const PdfToEmfConverter::StartCallback& start_callback) {
310 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 308 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
311 BrowserThread::PostTask( 309 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
312 BrowserThread::IO, FROM_HERE, 310 base::Bind(&PdfToEmfUtilityProcessHostClient::Start,
313 base::Bind(&PdfToEmfUtilityProcessHostClient::Start, this, data, 311 this, data, start_callback));
314 print_text_with_gdi, start_callback));
315 return; 312 return;
316 } 313 }
317 314
318 // Store callback before any OnFailed() call to make it called on failure. 315 // Store callback before any OnFailed() call to make it called on failure.
319 start_callback_ = start_callback; 316 start_callback_ = start_callback;
320 317
321 // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load 318 // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load
322 // gdiplus.dll, change how rendering happens, and not be able to correctly 319 // gdiplus.dll, change how rendering happens, and not be able to correctly
323 // generate when sent to a metafile DC. 320 // generate when sent to a metafile DC.
324 utility_process_host_ = content::UtilityProcessHost::Create( 321 utility_process_host_ = content::UtilityProcessHost::Create(
325 this, base::ThreadTaskRunnerHandle::Get()) 322 this, base::ThreadTaskRunnerHandle::Get())
326 ->AsWeakPtr(); 323 ->AsWeakPtr();
327 utility_process_host_->SetName(l10n_util::GetStringUTF16( 324 utility_process_host_->SetName(l10n_util::GetStringUTF16(
328 IDS_UTILITY_PROCESS_EMF_CONVERTOR_NAME)); 325 IDS_UTILITY_PROCESS_EMF_CONVERTOR_NAME));
329 326
330 BrowserThread::PostTaskAndReplyWithResult( 327 BrowserThread::PostTaskAndReplyWithResult(
331 BrowserThread::FILE, FROM_HERE, 328 BrowserThread::FILE, FROM_HERE,
332 base::Bind(&CreateTempPdfFile, data, &temp_dir_), 329 base::Bind(&CreateTempPdfFile, data, &temp_dir_),
333 base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this, 330 base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this));
334 print_text_with_gdi));
335 } 331 }
336 332
337 void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(bool print_text_with_gdi, 333 void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) {
338 ScopedTempFile pdf) {
339 DCHECK_CURRENTLY_ON(BrowserThread::IO); 334 DCHECK_CURRENTLY_ON(BrowserThread::IO);
340 if (!utility_process_host_ || !pdf) 335 if (!utility_process_host_ || !pdf)
341 return OnFailed(); 336 return OnFailed();
342 // Should reply with OnPageCount(). 337 // Should reply with OnPageCount().
343 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles( 338 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(
344 IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false), settings_, 339 IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false),
345 print_text_with_gdi)); 340 settings_));
346 } 341 }
347 342
348 void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) { 343 void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) {
349 DCHECK_CURRENTLY_ON(BrowserThread::IO); 344 DCHECK_CURRENTLY_ON(BrowserThread::IO);
350 if (start_callback_.is_null()) 345 if (start_callback_.is_null())
351 return OnFailed(); 346 return OnFailed();
352 BrowserThread::PostTask(BrowserThread::UI, 347 BrowserThread::PostTask(BrowserThread::UI,
353 FROM_HERE, 348 FROM_HERE,
354 base::Bind(&PdfToEmfConverterImpl::RunCallback, 349 base::Bind(&PdfToEmfConverterImpl::RunCallback,
355 converter_, 350 converter_,
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
512 } 507 }
513 508
514 PdfToEmfConverterImpl::~PdfToEmfConverterImpl() { 509 PdfToEmfConverterImpl::~PdfToEmfConverterImpl() {
515 if (utility_client_.get()) 510 if (utility_client_.get())
516 utility_client_->Stop(); 511 utility_client_->Stop();
517 } 512 }
518 513
519 void PdfToEmfConverterImpl::Start( 514 void PdfToEmfConverterImpl::Start(
520 const scoped_refptr<base::RefCountedMemory>& data, 515 const scoped_refptr<base::RefCountedMemory>& data,
521 const PdfRenderSettings& conversion_settings, 516 const PdfRenderSettings& conversion_settings,
522 bool print_text_with_gdi,
523 const StartCallback& start_callback) { 517 const StartCallback& start_callback) {
524 DCHECK(!utility_client_.get()); 518 DCHECK(!utility_client_.get());
525 utility_client_ = new PdfToEmfUtilityProcessHostClient( 519 utility_client_ = new PdfToEmfUtilityProcessHostClient(
526 weak_ptr_factory_.GetWeakPtr(), conversion_settings); 520 weak_ptr_factory_.GetWeakPtr(), conversion_settings);
527 utility_client_->Start(data, print_text_with_gdi, start_callback); 521 utility_client_->Start(data, start_callback);
528 } 522 }
529 523
530 void PdfToEmfConverterImpl::GetPage(int page_number, 524 void PdfToEmfConverterImpl::GetPage(int page_number,
531 const GetPageCallback& get_page_callback) { 525 const GetPageCallback& get_page_callback) {
532 utility_client_->GetPage(page_number, get_page_callback); 526 utility_client_->GetPage(page_number, get_page_callback);
533 } 527 }
534 528
535 void PdfToEmfConverterImpl::RunCallback(const base::Closure& callback) { 529 void PdfToEmfConverterImpl::RunCallback(const base::Closure& callback) {
536 DCHECK_CURRENTLY_ON(BrowserThread::UI); 530 DCHECK_CURRENTLY_ON(BrowserThread::UI);
537 callback.Run(); 531 callback.Run();
538 } 532 }
539 533
534 // See LazyEmf/RefCountedTempDir comments for why it is also needed here.
535 // Maybe combine the two classes since they are so similar.
536 class PostScriptMetaFile : public MetafilePlayer {
537 public:
Vitaly Buka (NO REVIEWS) 2017/01/17 19:29:16 To much of duplicated code. Could you just do publ
538 PostScriptMetaFile(const scoped_refptr<RefCountedTempDir>& temp_dir,
539 ScopedTempFile file)
540 : temp_dir_(temp_dir), file_(std::move(file)) {
541 CHECK(file_);
542 }
543 ~PostScriptMetaFile() override { Close(); }
544
545 private:
546 // MetafilePlayer:
547 bool SafePlayback(HDC hdc) const override;
548 bool GetDataAsVector(std::vector<char>* buffer) const override;
549 bool SaveTo(base::File* file) const override;
550
551 void Close() const;
552 bool LoadEmf(Emf* emf) const;
553
554 mutable scoped_refptr<RefCountedTempDir> temp_dir_;
555 mutable ScopedTempFile file_; // Mutable because of consts in base class.
556
557 DISALLOW_COPY_AND_ASSIGN(PostScriptMetaFile);
558 };
559
560 bool PostScriptMetaFile::SafePlayback(HDC hdc) const {
561 // TODO(thestig): Fix destruction of metafiles. For some reasons
562 // instances of Emf are not deleted. https://crbug.com/260806
563 // It's known that the Emf going to be played just once to a printer. So just
564 // release |file_| before returning.
565 Emf emf;
566 if (!LoadEmf(&emf)) {
567 Close();
568 return false;
569 }
570
571 {
572 // Ensure enumerator destruction before calling Close() below.
573 Emf::Enumerator emf_enum(emf, nullptr, nullptr);
574 for (const Emf::Record& record : emf_enum) {
575 auto* emf_record = record.record();
576 if (emf_record->iType != EMR_GDICOMMENT)
577 continue;
578
579 const EMRGDICOMMENT* comment =
580 reinterpret_cast<const EMRGDICOMMENT*>(emf_record);
581 const char* data = reinterpret_cast<const char*>(comment->Data);
582 const uint16_t* ptr = reinterpret_cast<const uint16_t*>(data);
583 int ret = ExtEscape(hdc, PASSTHROUGH, 2 + *ptr, data, 0, nullptr);
584 DCHECK_EQ(*ptr, ret);
585 }
586 }
587 Close();
588 return true;
589 }
590
591 bool PostScriptMetaFile::GetDataAsVector(std::vector<char>* buffer) const {
592 NOTREACHED();
593 return false;
594 }
595
596 bool PostScriptMetaFile::SaveTo(base::File* file) const {
597 Emf emf;
598 return LoadEmf(&emf) && emf.SaveTo(file);
599 }
600
601 void PostScriptMetaFile::Close() const {
602 file_.reset();
603 temp_dir_ = nullptr;
604 }
605
606 bool PostScriptMetaFile::LoadEmf(Emf* emf) const {
607 file_->Seek(base::File::FROM_BEGIN, 0);
608 int64_t size = file_->GetLength();
609 if (size <= 0)
610 return false;
611 std::vector<char> data(size);
612 if (file_->ReadAtCurrentPos(data.data(), data.size()) != size)
613 return false;
614 return emf->InitFromData(data.data(), data.size());
615 }
616
617 class PdfToPostScriptConverterImpl;
618
619 // Converts PDF into PostScript.
620 // Class uses 3 threads: UI, IO and FILE.
621 // Internal workflow is following:
622 // 1. Create instance on the UI thread. (files_, settings_,)
623 // 2. Create pdf file on the FILE thread.
624 // 3. Start utility process and start conversion on the IO thread.
625 // 4. Utility process returns page count.
626 // 5. For each page:
627 // 1. Clients requests page with file handle to a temp file.
628 // 2. Utility converts the page, save it to the file and reply.
629 //
630 // All these steps work sequentially, so no data should be accessed
631 // simultaneously by several threads.
632 class PdfToPostScriptUtilityProcessHostClient
633 : public content::UtilityProcessHostClient {
634 public:
635 PdfToPostScriptUtilityProcessHostClient(
636 base::WeakPtr<PdfToPostScriptConverterImpl> converter,
637 const PdfRenderSettings& settings);
638
639 void Start(const scoped_refptr<base::RefCountedMemory>& data,
640 const PdfToPostScriptConverter::StartCallback& start_callback);
641
642 void GetPage(
643 int page_number,
644 const PdfToPostScriptConverter::GetPageCallback& get_page_callback);
645
646 void Stop();
647
648 // UtilityProcessHostClient implementation.
649 void OnProcessCrashed(int exit_code) override;
650 void OnProcessLaunchFailed(int exit_code) override;
651 bool OnMessageReceived(const IPC::Message& message) override;
652
653 private:
654 class GetPageCallbackData {
655 public:
656 GetPageCallbackData(
657 int page_number,
658 const PdfToPostScriptConverter::GetPageCallback& callback)
659 : page_number_(page_number), callback_(callback) {}
660
661 GetPageCallbackData(GetPageCallbackData&& other) {
662 *this = std::move(other);
663 }
664
665 GetPageCallbackData& operator=(GetPageCallbackData&& rhs) {
666 page_number_ = rhs.page_number_;
667 callback_ = rhs.callback_;
668 ps_ = std::move(rhs.ps_);
669 return *this;
670 }
671
672 int page_number() const { return page_number_; }
673 const PdfToPostScriptConverter::GetPageCallback& callback() const {
674 return callback_;
675 }
676 ScopedTempFile TakePostScript() { return std::move(ps_); }
677 void set_ps(ScopedTempFile ps) { ps_ = std::move(ps); }
678
679 private:
680 int page_number_;
681 PdfToPostScriptConverter::GetPageCallback callback_;
682 ScopedTempFile ps_;
683
684 DISALLOW_COPY_AND_ASSIGN(GetPageCallbackData);
685 };
686
687 ~PdfToPostScriptUtilityProcessHostClient() override;
688
689 bool Send(IPC::Message* msg);
690
691 // Message handlers.
692 void OnPageCount(int page_count);
693 void OnPageDone(bool success);
694
695 void OnFailed();
696 void OnTempPdfReady(ScopedTempFile pdf);
697 void OnTempPostScriptReady(GetPageCallbackData* callback_data,
698 ScopedTempFile ps);
699
700 scoped_refptr<RefCountedTempDir> temp_dir_;
701
702 // Used to suppress callbacks after PdfToPostScriptConverterImpl is deleted.
703 base::WeakPtr<PdfToPostScriptConverterImpl> converter_;
704 PdfRenderSettings settings_;
705
706 // Document loaded callback.
707 PdfToPostScriptConverter::StartCallback start_callback_;
708
709 // Process host for IPC.
710 base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
711
712 // Queue of callbacks for GetPage() requests. Utility process should reply
713 // with PageDone in the same order as requests were received.
714 // Use containers that keeps element pointers valid after push() and pop().
715 using GetPageCallbacks = std::queue<GetPageCallbackData>;
716 GetPageCallbacks get_page_callbacks_;
717
718 DISALLOW_COPY_AND_ASSIGN(PdfToPostScriptUtilityProcessHostClient);
719 };
720
721 class PdfToPostScriptConverterImpl : public PdfToPostScriptConverter {
722 public:
723 PdfToPostScriptConverterImpl();
724 ~PdfToPostScriptConverterImpl() override;
725
726 void Start(const scoped_refptr<base::RefCountedMemory>& data,
727 const PdfRenderSettings& conversion_settings,
728 const StartCallback& start_callback) override;
729
730 void GetPage(int page_number,
731 const GetPageCallback& get_page_callback) override;
732
733 // Helps to cancel callbacks if this object is destroyed.
734 void RunCallback(const base::Closure& callback);
735
736 private:
737 scoped_refptr<PdfToPostScriptUtilityProcessHostClient> utility_client_;
738 base::WeakPtrFactory<PdfToPostScriptConverterImpl> weak_ptr_factory_;
739
740 DISALLOW_COPY_AND_ASSIGN(PdfToPostScriptConverterImpl);
741 };
742
743 PdfToPostScriptUtilityProcessHostClient::
744 PdfToPostScriptUtilityProcessHostClient(
745 base::WeakPtr<PdfToPostScriptConverterImpl> converter,
746 const PdfRenderSettings& settings)
747 : converter_(converter), settings_(settings) {}
748
749 PdfToPostScriptUtilityProcessHostClient::
750 ~PdfToPostScriptUtilityProcessHostClient() {}
751
752 void PdfToPostScriptUtilityProcessHostClient::Start(
753 const scoped_refptr<base::RefCountedMemory>& data,
754 const PdfToPostScriptConverter::StartCallback& start_callback) {
755 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
756 BrowserThread::PostTask(
757 BrowserThread::IO, FROM_HERE,
758 base::Bind(&PdfToPostScriptUtilityProcessHostClient::Start, this, data,
759 start_callback));
760 return;
761 }
762 // Store callback before any OnFailed() call to make it called on failure.
763 start_callback_ = start_callback;
764
765 // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load
766 // gdiplus.dll, change how rendering happens, and not be able to correctly
767 // generate when sent to a metafile DC.
768 utility_process_host_ = content::UtilityProcessHost::Create(
769 this, base::ThreadTaskRunnerHandle::Get())
770 ->AsWeakPtr();
771 utility_process_host_->SetName(
772 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_PS_CONVERTOR_NAME));
773
774 BrowserThread::PostTaskAndReplyWithResult(
775 BrowserThread::FILE, FROM_HERE,
776 base::Bind(&CreateTempPdfFile, data, &temp_dir_),
777 base::Bind(&PdfToPostScriptUtilityProcessHostClient::OnTempPdfReady,
778 this));
779 }
780
781 void PdfToPostScriptUtilityProcessHostClient::OnTempPdfReady(
782 ScopedTempFile pdf) {
783 DCHECK_CURRENTLY_ON(BrowserThread::IO);
784 if (!utility_process_host_ || !pdf)
785 return OnFailed();
786 // Should reply with OnPageCount().
787 Send(new ChromeUtilityMsg_RenderPDFPagesToPostScript_Start(
788 IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false),
789 settings_));
790 }
791
792 void PdfToPostScriptUtilityProcessHostClient::OnPageCount(int page_count) {
793 DCHECK_CURRENTLY_ON(BrowserThread::IO);
794 if (start_callback_.is_null())
795 return OnFailed();
796 BrowserThread::PostTask(
797 BrowserThread::UI, FROM_HERE,
798 base::Bind(&PdfToPostScriptConverterImpl::RunCallback, converter_,
799 base::Bind(start_callback_, page_count)));
800 start_callback_.Reset();
801 }
802
803 void PdfToPostScriptUtilityProcessHostClient::GetPage(
804 int page_number,
805 const PdfToPostScriptConverter::GetPageCallback& get_page_callback) {
806 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
807 BrowserThread::PostTask(
808 BrowserThread::IO, FROM_HERE,
809 base::Bind(&PdfToPostScriptUtilityProcessHostClient::GetPage, this,
810 page_number, get_page_callback));
811 return;
812 }
813 // Store callback before any OnFailed() call to make it called on failure.
814 get_page_callbacks_.push(GetPageCallbackData(page_number, get_page_callback));
815
816 if (!utility_process_host_)
817 return OnFailed();
818
819 BrowserThread::PostTaskAndReplyWithResult(
820 BrowserThread::FILE, FROM_HERE, base::Bind(&CreateTempFile, &temp_dir_),
821 base::Bind(
822 &PdfToPostScriptUtilityProcessHostClient::OnTempPostScriptReady, this,
823 &get_page_callbacks_.back()));
824 }
825
826 void PdfToPostScriptUtilityProcessHostClient::OnTempPostScriptReady(
827 GetPageCallbackData* callback_data,
828 ScopedTempFile ps) {
829 DCHECK_CURRENTLY_ON(BrowserThread::IO);
830 if (!utility_process_host_ || !ps)
831 return OnFailed();
832 IPC::PlatformFileForTransit transit =
833 IPC::GetPlatformFileForTransit(ps->GetPlatformFile(), false);
834 callback_data->set_ps(std::move(ps));
835 // Should reply with OnPageDone().
836 Send(new ChromeUtilityMsg_RenderPDFPagesToPostScript_GetPage(
837 callback_data->page_number(), transit));
838 }
839
840 void PdfToPostScriptUtilityProcessHostClient::OnPageDone(bool success) {
841 DCHECK_CURRENTLY_ON(BrowserThread::IO);
842 if (get_page_callbacks_.empty())
843 return OnFailed();
844 GetPageCallbackData& data = get_page_callbacks_.front();
845 std::unique_ptr<PostScriptMetaFile> ps_metafile;
846
847 if (success) {
848 ScopedTempFile temp_ps = data.TakePostScript();
849 if (!temp_ps) // Unexpected message from utility process.
850 return OnFailed();
851 ps_metafile =
852 base::MakeUnique<PostScriptMetaFile>(temp_dir_, std::move(temp_ps));
853 }
854
855 BrowserThread::PostTask(
856 BrowserThread::UI, FROM_HERE,
857 base::Bind(&PdfToPostScriptConverterImpl::RunCallback, converter_,
858 base::Bind(data.callback(), data.page_number(),
859 base::Passed(&ps_metafile))));
860 get_page_callbacks_.pop();
861 }
862
863 void PdfToPostScriptUtilityProcessHostClient::Stop() {
864 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
865 BrowserThread::PostTask(
866 BrowserThread::IO, FROM_HERE,
867 base::Bind(&PdfToPostScriptUtilityProcessHostClient::Stop, this));
868 return;
869 }
870 Send(new ChromeUtilityMsg_RenderPDFPagesToPostScript_Stop());
871 }
872
873 void PdfToPostScriptUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
874 OnFailed();
875 }
876
877 void PdfToPostScriptUtilityProcessHostClient::OnProcessLaunchFailed(
878 int exit_code) {
879 OnFailed();
880 }
881
882 bool PdfToPostScriptUtilityProcessHostClient::OnMessageReceived(
883 const IPC::Message& message) {
884 bool handled = true;
885 IPC_BEGIN_MESSAGE_MAP(PdfToPostScriptUtilityProcessHostClient, message)
886 IPC_MESSAGE_HANDLER(
887 ChromeUtilityHostMsg_RenderPDFPagesToPostScript_PageCount, OnPageCount)
888 IPC_MESSAGE_HANDLER(
889 ChromeUtilityHostMsg_RenderPDFPagesToPostScript_PageDone, OnPageDone)
890 IPC_MESSAGE_UNHANDLED(handled = false)
891 IPC_END_MESSAGE_MAP()
892 return handled;
893 }
894
895 bool PdfToPostScriptUtilityProcessHostClient::Send(IPC::Message* msg) {
896 if (utility_process_host_)
897 return utility_process_host_->Send(msg);
898 delete msg;
899 return false;
900 }
901
902 void PdfToPostScriptUtilityProcessHostClient::OnFailed() {
903 DCHECK_CURRENTLY_ON(BrowserThread::IO);
904 if (!start_callback_.is_null())
905 OnPageCount(0);
906 while (!get_page_callbacks_.empty())
907 OnPageDone(false);
908 utility_process_host_.reset();
909 }
910
911 PdfToPostScriptConverterImpl::PdfToPostScriptConverterImpl()
912 : weak_ptr_factory_(this) {}
913
914 PdfToPostScriptConverterImpl::~PdfToPostScriptConverterImpl() {
915 if (utility_client_.get())
916 utility_client_->Stop();
917 }
918
919 void PdfToPostScriptConverterImpl::Start(
920 const scoped_refptr<base::RefCountedMemory>& data,
921 const PdfRenderSettings& conversion_settings,
922 const StartCallback& start_callback) {
923 DCHECK(!utility_client_.get());
924 utility_client_ = new PdfToPostScriptUtilityProcessHostClient(
925 weak_ptr_factory_.GetWeakPtr(), conversion_settings);
926 utility_client_->Start(data, start_callback);
927 }
928
929 void PdfToPostScriptConverterImpl::GetPage(
930 int page_number,
931 const GetPageCallback& get_page_callback) {
932 utility_client_->GetPage(page_number, get_page_callback);
933 }
934
935 void PdfToPostScriptConverterImpl::RunCallback(const base::Closure& callback) {
936 DCHECK_CURRENTLY_ON(BrowserThread::UI);
937 callback.Run();
938 }
939
540 } // namespace 940 } // namespace
541 941
542 PdfToEmfConverter::~PdfToEmfConverter() { 942 PdfToEmfConverter::~PdfToEmfConverter() {}
543 }
544 943
545 // static 944 // static
546 std::unique_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { 945 std::unique_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() {
547 return std::unique_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); 946 return base::MakeUnique<PdfToEmfConverterImpl>();
947 }
948
949 PdfToPostScriptConverter::~PdfToPostScriptConverter() {}
950
951 // static
952 std::unique_ptr<PdfToPostScriptConverter>
953 PdfToPostScriptConverter::CreateDefault() {
954 return base::MakeUnique<PdfToPostScriptConverterImpl>();
548 } 955 }
549 956
550 } // namespace printing 957 } // namespace printing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698