pdf_to_emf_converter.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  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
  3. // found in the LICENSE file.
  4. #include "chrome/browser/printing/pdf_to_emf_converter.h"
  5. #include <stdint.h>
  6. #include <windows.h>
  7. #include <memory>
  8. #include <queue>
  9. #include <utility>
  10. #include <vector>
  11. #include "base/files/file.h"
  12. #include "base/files/file_util.h"
  13. #include "base/files/scoped_temp_dir.h"
  14. #include "base/logging.h"
  15. #include "base/macros.h"
  16. #include "base/threading/thread_task_runner_handle.h"
  17. #include "chrome/common/chrome_utility_printing_messages.h"
  18. #include "content/public/browser/browser_thread.h"
  19. #include "content/public/browser/child_process_data.h"
  20. #include "content/public/browser/utility_process_host.h"
  21. #include "content/public/browser/utility_process_host_client.h"
  22. #include "printing/emf_win.h"
  23. #include "printing/pdf_render_settings.h"
  24. #include "ui/base/l10n/l10n_util.h"
  25. using content::BrowserThread;
  26. namespace printing {
  27. namespace {
  28. class PdfConverterImpl;
  29. // Allows to delete temporary directory after all temporary files created inside
  30. // are closed. Windows cannot delete directory with opened files. Directory is
  31. // used to store PDF and metafiles. PDF should be gone by the time utility
  32. // process exits. Metafiles should be gone when all LazyEmf destroyed.
  33. class RefCountedTempDir
  34. : public base::RefCountedThreadSafe<RefCountedTempDir,
  35. BrowserThread::DeleteOnFileThread> {
  36. public:
  37. RefCountedTempDir() { ignore_result(temp_dir_.CreateUniqueTempDir()); }
  38. bool IsValid() const { return temp_dir_.IsValid(); }
  39. const base::FilePath& GetPath() const { return temp_dir_.GetPath(); }
  40. private:
  41. friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
  42. friend class base::DeleteHelper<RefCountedTempDir>;
  43. ~RefCountedTempDir() {}
  44. base::ScopedTempDir temp_dir_;
  45. DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir);
  46. };
  47. using ScopedTempFile =
  48. std::unique_ptr<base::File, BrowserThread::DeleteOnFileThread>;
  49. // Wrapper for Emf to keep only file handle in memory, and load actual data only
  50. // on playback. Emf::InitFromFile() can play metafile directly from disk, but it
  51. // can't open file handles. We need file handles to reliably delete temporary
  52. // files, and to efficiently interact with utility process.
  53. class LazyEmf : public MetafilePlayer {
  54. public:
  55. LazyEmf(const scoped_refptr<RefCountedTempDir>& temp_dir, ScopedTempFile file)
  56. : temp_dir_(temp_dir), file_(std::move(file)) {
  57. CHECK(file_);
  58. }
  59. ~LazyEmf() override { Close(); }
  60. protected:
  61. // MetafilePlayer:
  62. bool SafePlayback(HDC hdc) const override;
  63. void Close() const;
  64. bool LoadEmf(Emf* emf) const;
  65. private:
  66. mutable scoped_refptr<RefCountedTempDir> temp_dir_;
  67. mutable ScopedTempFile file_; // Mutable because of consts in base class.
  68. bool GetDataAsVector(std::vector<char>* buffer) const override;
  69. bool SaveTo(base::File* file) const override;
  70. DISALLOW_COPY_AND_ASSIGN(LazyEmf);
  71. };
  72. // Postscript metafile subclass to override SafePlayback.
  73. class PostScriptMetaFile : public LazyEmf {
  74. public:
  75. PostScriptMetaFile(const scoped_refptr<RefCountedTempDir>& temp_dir,
  76. ScopedTempFile file)
  77. : LazyEmf(temp_dir, std::move(file)) {}
  78. ~PostScriptMetaFile() override;
  79. protected:
  80. // MetafilePlayer:
  81. bool SafePlayback(HDC hdc) const override;
  82. DISALLOW_COPY_AND_ASSIGN(PostScriptMetaFile);
  83. };
  84. // Class for converting PDF to another format for printing (Emf, Postscript).
  85. // Class uses 3 threads: UI, IO and FILE.
  86. // Internal workflow is following:
  87. // 1. Create instance on the UI thread. (files_, settings_,)
  88. // 2. Create pdf file on the FILE thread.
  89. // 3. Start utility process and start conversion on the IO thread.
  90. // 4. Utility process returns page count.
  91. // 5. For each page:
  92. // 1. Clients requests page with file handle to a temp file.
  93. // 2. Utility converts the page, save it to the file and reply.
  94. //
  95. // All these steps work sequentially, so no data should be accessed
  96. // simultaneously by several threads.
  97. class PdfConverterUtilityProcessHostClient
  98. : public content::UtilityProcessHostClient {
  99. public:
  100. PdfConverterUtilityProcessHostClient(
  101. base::WeakPtr<PdfConverterImpl> converter,
  102. const PdfRenderSettings& settings);
  103. void Start(const scoped_refptr<base::RefCountedMemory>& data,
  104. const PdfConverter::StartCallback& start_callback);
  105. void GetPage(int page_number,
  106. const PdfConverter::GetPageCallback& get_page_callback);
  107. void Stop();
  108. // UtilityProcessHostClient implementation.
  109. void OnProcessCrashed(int exit_code) override;
  110. void OnProcessLaunchFailed(int exit_code) override;
  111. // Needs to be public to handle ChromeUtilityHostMsg_PreCacheFontCharacters
  112. // sync message replies.
  113. bool Send(IPC::Message* msg);
  114. protected:
  115. class GetPageCallbackData {
  116. public:
  117. GetPageCallbackData(int page_number, PdfConverter::GetPageCallback callback)
  118. : page_number_(page_number), callback_(callback) {}
  119. GetPageCallbackData(GetPageCallbackData&& other) {
  120. *this = std::move(other);
  121. }
  122. GetPageCallbackData& operator=(GetPageCallbackData&& rhs) {
  123. page_number_ = rhs.page_number_;
  124. callback_ = rhs.callback_;
  125. file_ = std::move(rhs.file_);
  126. return *this;
  127. }
  128. int page_number() const { return page_number_; }
  129. const PdfConverter::GetPageCallback& callback() const { return callback_; }
  130. ScopedTempFile TakeFile() { return std::move(file_); }
  131. void set_file(ScopedTempFile file) { file_ = std::move(file); }
  132. private:
  133. int page_number_;
  134. PdfConverter::GetPageCallback callback_;
  135. ScopedTempFile file_;
  136. DISALLOW_COPY_AND_ASSIGN(GetPageCallbackData);
  137. };
  138. ~PdfConverterUtilityProcessHostClient() override;
  139. bool OnMessageReceived(const IPC::Message& message) override;
  140. // Helper functions: must be overridden by subclasses
  141. // Set the process name
  142. virtual base::string16 GetName() const;
  143. // Create a metafileplayer subclass file from a temporary file.
  144. virtual std::unique_ptr<MetafilePlayer> GetFileFromTemp(
  145. std::unique_ptr<base::File, content::BrowserThread::DeleteOnFileThread>
  146. temp_file);
  147. // Send the messages to Start, GetPage, and Stop.
  148. virtual void SendStartMessage(IPC::PlatformFileForTransit transit);
  149. virtual void SendGetPageMessage(int page_number,
  150. IPC::PlatformFileForTransit transit);
  151. virtual void SendStopMessage();
  152. // Message handlers:
  153. void OnPageCount(int page_count);
  154. void OnPageDone(bool success, float scale_factor);
  155. void OnFailed();
  156. void OnTempPdfReady(ScopedTempFile pdf);
  157. void OnTempFileReady(GetPageCallbackData* callback_data,
  158. ScopedTempFile temp_file);
  159. // Additional message handler needed for Pdf to Emf
  160. void OnPreCacheFontCharacters(const LOGFONT& log_font,
  161. const base::string16& characters);
  162. scoped_refptr<RefCountedTempDir> temp_dir_;
  163. // Used to suppress callbacks after PdfConverter is deleted.
  164. base::WeakPtr<PdfConverterImpl> converter_;
  165. PdfRenderSettings settings_;
  166. // Document loaded callback.
  167. PdfConverter::StartCallback start_callback_;
  168. // Process host for IPC.
  169. base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
  170. // Queue of callbacks for GetPage() requests. Utility process should reply
  171. // with PageDone in the same order as requests were received.
  172. // Use containers that keeps element pointers valid after push() and pop().
  173. using GetPageCallbacks = std::queue<GetPageCallbackData>;
  174. GetPageCallbacks get_page_callbacks_;
  175. DISALLOW_COPY_AND_ASSIGN(PdfConverterUtilityProcessHostClient);
  176. };
  177. std::unique_ptr<MetafilePlayer>
  178. PdfConverterUtilityProcessHostClient::GetFileFromTemp(
  179. std::unique_ptr<base::File, content::BrowserThread::DeleteOnFileThread>
  180. temp_file) {
  181. if (settings_.mode == PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2 ||
  182. settings_.mode == PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3) {
  183. return std::make_unique<PostScriptMetaFile>(temp_dir_,
  184. std::move(temp_file));
  185. }
  186. return std::make_unique<LazyEmf>(temp_dir_, std::move(temp_file));
  187. }
  188. class PdfConverterImpl : public PdfConverter {
  189. public:
  190. PdfConverterImpl();
  191. ~PdfConverterImpl() override;
  192. base::WeakPtr<PdfConverterImpl> GetWeakPtr() {
  193. return weak_ptr_factory_.GetWeakPtr();
  194. }
  195. void Start(const scoped_refptr<base::RefCountedMemory>& data,
  196. const PdfRenderSettings& conversion_settings,
  197. const StartCallback& start_callback);
  198. void GetPage(int page_number,
  199. const GetPageCallback& get_page_callback) override;
  200. // Helps to cancel callbacks if this object is destroyed.
  201. void RunCallback(const base::Closure& callback);
  202. void Start(
  203. const scoped_refptr<PdfConverterUtilityProcessHostClient>& utility_client,
  204. const scoped_refptr<base::RefCountedMemory>& data,
  205. const StartCallback& start_callback);
  206. private:
  207. scoped_refptr<PdfConverterUtilityProcessHostClient> utility_client_;
  208. base::WeakPtrFactory<PdfConverterImpl> weak_ptr_factory_;
  209. DISALLOW_COPY_AND_ASSIGN(PdfConverterImpl);
  210. };
  211. ScopedTempFile CreateTempFile(scoped_refptr<RefCountedTempDir>* temp_dir) {
  212. if (!temp_dir->get())
  213. *temp_dir = new RefCountedTempDir();
  214. ScopedTempFile file;
  215. if (!(*temp_dir)->IsValid())
  216. return file;
  217. base::FilePath path;
  218. if (!base::CreateTemporaryFileInDir((*temp_dir)->GetPath(), &path)) {
  219. PLOG(ERROR) << "Failed to create file in "
  220. << (*temp_dir)->GetPath().value();
  221. return file;
  222. }
  223. file.reset(new base::File(
  224. path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
  225. base::File::FLAG_READ | base::File::FLAG_DELETE_ON_CLOSE |
  226. base::File::FLAG_TEMPORARY));
  227. if (!file->IsValid()) {
  228. PLOG(ERROR) << "Failed to create " << path.value();
  229. file.reset();
  230. }
  231. return file;
  232. }
  233. ScopedTempFile CreateTempPdfFile(
  234. const scoped_refptr<base::RefCountedMemory>& data,
  235. scoped_refptr<RefCountedTempDir>* temp_dir) {
  236. DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  237. ScopedTempFile pdf_file = CreateTempFile(temp_dir);
  238. if (!pdf_file ||
  239. static_cast<int>(data->size()) !=
  240. pdf_file->WriteAtCurrentPos(data->front_as<char>(), data->size())) {
  241. pdf_file.reset();
  242. return pdf_file;
  243. }
  244. pdf_file->Seek(base::File::FROM_BEGIN, 0);
  245. return pdf_file;
  246. }
  247. bool LazyEmf::SafePlayback(HDC hdc) const {
  248. Emf emf;
  249. bool result = LoadEmf(&emf) && emf.SafePlayback(hdc);
  250. // TODO(thestig): Fix destruction of metafiles. For some reasons
  251. // instances of Emf are not deleted. https://crbug.com/260806
  252. // It's known that the Emf going to be played just once to a printer. So just
  253. // release |file_| here.
  254. Close();
  255. return result;
  256. }
  257. bool LazyEmf::GetDataAsVector(std::vector<char>* buffer) const {
  258. NOTREACHED();
  259. return false;
  260. }
  261. bool LazyEmf::SaveTo(base::File* file) const {
  262. Emf emf;
  263. return LoadEmf(&emf) && emf.SaveTo(file);
  264. }
  265. void LazyEmf::Close() const {
  266. file_.reset();
  267. temp_dir_ = nullptr;
  268. }
  269. bool LazyEmf::LoadEmf(Emf* emf) const {
  270. file_->Seek(base::File::FROM_BEGIN, 0);
  271. int64_t size = file_->GetLength();
  272. if (size <= 0)
  273. return false;
  274. std::vector<char> data(size);
  275. if (file_->ReadAtCurrentPos(data.data(), data.size()) != size)
  276. return false;
  277. return emf->InitFromData(data.data(), data.size());
  278. }
  279. PostScriptMetaFile::~PostScriptMetaFile() {}
  280. bool PostScriptMetaFile::SafePlayback(HDC hdc) const {
  281. // TODO(thestig): Fix destruction of metafiles. For some reasons
  282. // instances of Emf are not deleted. https://crbug.com/260806
  283. // It's known that the Emf going to be played just once to a printer. So just
  284. // release |file_| before returning.
  285. Emf emf;
  286. if (!LoadEmf(&emf)) {
  287. Close();
  288. return false;
  289. }
  290. {
  291. // Ensure enumerator destruction before calling Close() below.
  292. Emf::Enumerator emf_enum(emf, nullptr, nullptr);
  293. for (const Emf::Record& record : emf_enum) {
  294. auto* emf_record = record.record();
  295. if (emf_record->iType != EMR_GDICOMMENT)
  296. continue;
  297. const EMRGDICOMMENT* comment =
  298. reinterpret_cast<const EMRGDICOMMENT*>(emf_record);
  299. const char* data = reinterpret_cast<const char*>(comment->Data);
  300. const uint16_t* ptr = reinterpret_cast<const uint16_t*>(data);
  301. int ret = ExtEscape(hdc, PASSTHROUGH, 2 + *ptr, data, 0, nullptr);
  302. DCHECK_EQ(*ptr, ret);
  303. }
  304. }
  305. Close();
  306. return true;
  307. }
  308. PdfConverterUtilityProcessHostClient::PdfConverterUtilityProcessHostClient(
  309. base::WeakPtr<PdfConverterImpl> converter,
  310. const PdfRenderSettings& settings)
  311. : converter_(converter), settings_(settings) {}
  312. PdfConverterUtilityProcessHostClient::~PdfConverterUtilityProcessHostClient() {}
  313. void PdfConverterUtilityProcessHostClient::Start(
  314. const scoped_refptr<base::RefCountedMemory>& data,
  315. const PdfConverter::StartCallback& start_callback) {
  316. if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
  317. BrowserThread::PostTask(
  318. BrowserThread::IO, FROM_HERE,
  319. base::Bind(&PdfConverterUtilityProcessHostClient::Start, this, data,
  320. start_callback));
  321. return;
  322. }
  323. // Store callback before any OnFailed() call to make it called on failure.
  324. start_callback_ = start_callback;
  325. // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load
  326. // gdiplus.dll, change how rendering happens, and not be able to correctly
  327. // generate when sent to a metafile DC.
  328. utility_process_host_ = content::UtilityProcessHost::Create(
  329. this, base::ThreadTaskRunnerHandle::Get())
  330. ->AsWeakPtr();
  331. utility_process_host_->SetName(GetName());
  332. BrowserThread::PostTaskAndReplyWithResult(
  333. BrowserThread::FILE, FROM_HERE,
  334. base::Bind(&CreateTempPdfFile, data, &temp_dir_),
  335. base::Bind(&PdfConverterUtilityProcessHostClient::OnTempPdfReady, this));
  336. }
  337. void PdfConverterUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) {
  338. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  339. if (!utility_process_host_ || !pdf)
  340. return OnFailed();
  341. // Should reply with OnPageCount().
  342. SendStartMessage(
  343. IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false));
  344. }
  345. void PdfConverterUtilityProcessHostClient::OnPageCount(int page_count) {
  346. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  347. if (start_callback_.is_null())
  348. return OnFailed();
  349. BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
  350. base::Bind(&PdfConverterImpl::RunCallback, converter_,
  351. base::Bind(start_callback_, page_count)));
  352. start_callback_.Reset();
  353. }
  354. void PdfConverterUtilityProcessHostClient::GetPage(
  355. int page_number,
  356. const PdfConverter::GetPageCallback& get_page_callback) {
  357. if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
  358. BrowserThread::PostTask(
  359. BrowserThread::IO, FROM_HERE,
  360. base::Bind(&PdfConverterUtilityProcessHostClient::GetPage, this,
  361. page_number, get_page_callback));
  362. return;
  363. }
  364. // Store callback before any OnFailed() call to make it called on failure.
  365. get_page_callbacks_.push(GetPageCallbackData(page_number, get_page_callback));
  366. if (!utility_process_host_)
  367. return OnFailed();
  368. BrowserThread::PostTaskAndReplyWithResult(
  369. BrowserThread::FILE, FROM_HERE, base::Bind(&CreateTempFile, &temp_dir_),
  370. base::Bind(&PdfConverterUtilityProcessHostClient::OnTempFileReady, this,
  371. &get_page_callbacks_.back()));
  372. }
  373. void PdfConverterUtilityProcessHostClient::OnTempFileReady(
  374. GetPageCallbackData* callback_data,
  375. ScopedTempFile temp_file) {
  376. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  377. if (!utility_process_host_ || !temp_file)
  378. return OnFailed();
  379. IPC::PlatformFileForTransit transit =
  380. IPC::GetPlatformFileForTransit(temp_file->GetPlatformFile(), false);
  381. callback_data->set_file(std::move(temp_file));
  382. // Should reply with OnPageDone().
  383. SendGetPageMessage(callback_data->page_number(), transit);
  384. }
  385. void PdfConverterUtilityProcessHostClient::OnPageDone(bool success,
  386. float scale_factor) {
  387. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  388. if (get_page_callbacks_.empty())
  389. return OnFailed();
  390. GetPageCallbackData& data = get_page_callbacks_.front();
  391. std::unique_ptr<MetafilePlayer> file;
  392. if (success) {
  393. ScopedTempFile temp_file = data.TakeFile();
  394. if (!temp_file) // Unexpected message from utility process.
  395. return OnFailed();
  396. file = GetFileFromTemp(std::move(temp_file));
  397. }
  398. BrowserThread::PostTask(
  399. BrowserThread::UI, FROM_HERE,
  400. base::Bind(&PdfConverterImpl::RunCallback, converter_,
  401. base::Bind(data.callback(), data.page_number(), scale_factor,
  402. base::Passed(&file))));
  403. get_page_callbacks_.pop();
  404. }
  405. void PdfConverterUtilityProcessHostClient::Stop() {
  406. if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
  407. BrowserThread::PostTask(
  408. BrowserThread::IO, FROM_HERE,
  409. base::Bind(&PdfConverterUtilityProcessHostClient::Stop, this));
  410. return;
  411. }
  412. SendStopMessage();
  413. }
  414. void PdfConverterUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
  415. OnFailed();
  416. }
  417. void PdfConverterUtilityProcessHostClient::OnProcessLaunchFailed(
  418. int exit_code) {
  419. OnFailed();
  420. }
  421. bool PdfConverterUtilityProcessHostClient::Send(IPC::Message* msg) {
  422. if (utility_process_host_)
  423. return utility_process_host_->Send(msg);
  424. delete msg;
  425. return false;
  426. }
  427. void PdfConverterUtilityProcessHostClient::OnFailed() {
  428. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  429. if (!start_callback_.is_null())
  430. OnPageCount(0);
  431. while (!get_page_callbacks_.empty())
  432. OnPageDone(false, 0.0f);
  433. utility_process_host_.reset();
  434. }
  435. void PdfConverterUtilityProcessHostClient::OnPreCacheFontCharacters(
  436. const LOGFONT& font,
  437. const base::string16& str) {
  438. // TODO(scottmg): pdf/ppapi still require the renderer to be able to precache
  439. // GDI fonts (http://crbug.com/383227), even when using DirectWrite.
  440. // Eventually this shouldn't be added and should be moved to
  441. // FontCacheDispatcher too. http://crbug.com/356346.
  442. // First, comments from FontCacheDispatcher::OnPreCacheFont do apply here too.
  443. // Except that for True Type fonts,
  444. // GetTextMetrics will not load the font in memory.
  445. // The only way windows seem to load properly, it is to create a similar
  446. // device (like the one in which we print), then do an ExtTextOut,
  447. // as we do in the printing thread, which is sandboxed.
  448. HDC hdc = CreateEnhMetaFile(nullptr, nullptr, nullptr, nullptr);
  449. HFONT font_handle = CreateFontIndirect(&font);
  450. DCHECK(font_handle != nullptr);
  451. HGDIOBJ old_font = SelectObject(hdc, font_handle);
  452. DCHECK(old_font != nullptr);
  453. ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, str.c_str(), str.length(), nullptr);
  454. SelectObject(hdc, old_font);
  455. DeleteObject(font_handle);
  456. HENHMETAFILE metafile = CloseEnhMetaFile(hdc);
  457. if (metafile)
  458. DeleteEnhMetaFile(metafile);
  459. }
  460. bool PdfConverterUtilityProcessHostClient::OnMessageReceived(
  461. const IPC::Message& message) {
  462. bool handled = true;
  463. IPC_BEGIN_MESSAGE_MAP(PdfConverterUtilityProcessHostClient, message)
  464. IPC_MESSAGE_HANDLER(
  465. ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount)
  466. IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone,
  467. OnPageDone)
  468. IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PreCacheFontCharacters,
  469. OnPreCacheFontCharacters)
  470. IPC_MESSAGE_UNHANDLED(handled = false)
  471. IPC_END_MESSAGE_MAP()
  472. return handled;
  473. }
  474. base::string16 PdfConverterUtilityProcessHostClient::GetName() const {
  475. return L"ChromeUtilityProcessPDFConvertor";
  476. }
  477. void PdfConverterUtilityProcessHostClient::SendGetPageMessage(
  478. int page_number,
  479. IPC::PlatformFileForTransit transit) {
  480. Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage(page_number,
  481. transit));
  482. }
  483. void PdfConverterUtilityProcessHostClient::SendStartMessage(
  484. IPC::PlatformFileForTransit transit) {
  485. Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(transit, settings_));
  486. }
  487. void PdfConverterUtilityProcessHostClient::SendStopMessage() {
  488. Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop());
  489. }
  490. // Pdf Converter Impl and subclasses
  491. PdfConverterImpl::PdfConverterImpl() : weak_ptr_factory_(this) {}
  492. PdfConverterImpl::~PdfConverterImpl() {
  493. if (utility_client_.get())
  494. utility_client_->Stop();
  495. }
  496. void PdfConverterImpl::Start(
  497. const scoped_refptr<PdfConverterUtilityProcessHostClient>& utility_client,
  498. const scoped_refptr<base::RefCountedMemory>& data,
  499. const StartCallback& start_callback) {
  500. DCHECK(!utility_client_);
  501. utility_client_ = utility_client;
  502. utility_client_->Start(data, start_callback);
  503. }
  504. void PdfConverterImpl::GetPage(int page_number,
  505. const GetPageCallback& get_page_callback) {
  506. utility_client_->GetPage(page_number, get_page_callback);
  507. }
  508. void PdfConverterImpl::RunCallback(const base::Closure& callback) {
  509. DCHECK_CURRENTLY_ON(BrowserThread::UI);
  510. callback.Run();
  511. }
  512. } // namespace
  513. PdfConverter::~PdfConverter() {}
  514. // static
  515. std::unique_ptr<PdfConverter> PdfConverter::StartPdfConverter(
  516. const scoped_refptr<base::RefCountedMemory>& data,
  517. const PdfRenderSettings& conversion_settings,
  518. const StartCallback& start_callback) {
  519. std::unique_ptr<PdfConverterImpl> converter =
  520. std::make_unique<PdfConverterImpl>();
  521. converter->Start(new PdfConverterUtilityProcessHostClient(
  522. converter->GetWeakPtr(), conversion_settings),
  523. data, start_callback);
  524. return std::move(converter);
  525. }
  526. } // namespace printing