Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |