123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "chrome/browser/printing/pdf_to_emf_converter.h"
- #include <stdint.h>
- #include <windows.h>
- #include <memory>
- #include <queue>
- #include <utility>
- #include <vector>
- #include "base/files/file.h"
- #include "base/files/file_util.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/logging.h"
- #include "base/macros.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "chrome/common/chrome_utility_printing_messages.h"
- #include "content/public/browser/browser_thread.h"
- #include "content/public/browser/child_process_data.h"
- #include "content/public/browser/utility_process_host.h"
- #include "content/public/browser/utility_process_host_client.h"
- #include "printing/emf_win.h"
- #include "printing/pdf_render_settings.h"
- #include "ui/base/l10n/l10n_util.h"
- using content::BrowserThread;
- namespace printing {
- namespace {
- class PdfConverterImpl;
- // Allows to delete temporary directory after all temporary files created inside
- // are closed. Windows cannot delete directory with opened files. Directory is
- // used to store PDF and metafiles. PDF should be gone by the time utility
- // process exits. Metafiles should be gone when all LazyEmf destroyed.
- class RefCountedTempDir
- : public base::RefCountedThreadSafe<RefCountedTempDir,
- BrowserThread::DeleteOnFileThread> {
- public:
- RefCountedTempDir() { ignore_result(temp_dir_.CreateUniqueTempDir()); }
- bool IsValid() const { return temp_dir_.IsValid(); }
- const base::FilePath& GetPath() const { return temp_dir_.GetPath(); }
- private:
- friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
- friend class base::DeleteHelper<RefCountedTempDir>;
- ~RefCountedTempDir() {}
- base::ScopedTempDir temp_dir_;
- DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir);
- };
- using ScopedTempFile =
- std::unique_ptr<base::File, BrowserThread::DeleteOnFileThread>;
- // Wrapper for Emf to keep only file handle in memory, and load actual data only
- // on playback. Emf::InitFromFile() can play metafile directly from disk, but it
- // can't open file handles. We need file handles to reliably delete temporary
- // files, and to efficiently interact with utility process.
- class LazyEmf : public MetafilePlayer {
- public:
- LazyEmf(const scoped_refptr<RefCountedTempDir>& temp_dir, ScopedTempFile file)
- : temp_dir_(temp_dir), file_(std::move(file)) {
- CHECK(file_);
- }
- ~LazyEmf() override { Close(); }
- protected:
- // MetafilePlayer:
- bool SafePlayback(HDC hdc) const override;
- void Close() const;
- bool LoadEmf(Emf* emf) const;
- private:
- mutable scoped_refptr<RefCountedTempDir> temp_dir_;
- mutable ScopedTempFile file_; // Mutable because of consts in base class.
- bool GetDataAsVector(std::vector<char>* buffer) const override;
- bool SaveTo(base::File* file) const override;
- DISALLOW_COPY_AND_ASSIGN(LazyEmf);
- };
- // Postscript metafile subclass to override SafePlayback.
- class PostScriptMetaFile : public LazyEmf {
- public:
- PostScriptMetaFile(const scoped_refptr<RefCountedTempDir>& temp_dir,
- ScopedTempFile file)
- : LazyEmf(temp_dir, std::move(file)) {}
- ~PostScriptMetaFile() override;
- protected:
- // MetafilePlayer:
- bool SafePlayback(HDC hdc) const override;
- DISALLOW_COPY_AND_ASSIGN(PostScriptMetaFile);
- };
- // Class for converting PDF to another format for printing (Emf, Postscript).
- // Class uses 3 threads: UI, IO and FILE.
- // Internal workflow is following:
- // 1. Create instance on the UI thread. (files_, settings_,)
- // 2. Create pdf file on the FILE thread.
- // 3. Start utility process and start conversion on the IO thread.
- // 4. Utility process returns page count.
- // 5. For each page:
- // 1. Clients requests page with file handle to a temp file.
- // 2. Utility converts the page, save it to the file and reply.
- //
- // All these steps work sequentially, so no data should be accessed
- // simultaneously by several threads.
- class PdfConverterUtilityProcessHostClient
- : public content::UtilityProcessHostClient {
- public:
- PdfConverterUtilityProcessHostClient(
- base::WeakPtr<PdfConverterImpl> converter,
- const PdfRenderSettings& settings);
- void Start(const scoped_refptr<base::RefCountedMemory>& data,
- const PdfConverter::StartCallback& start_callback);
- void GetPage(int page_number,
- const PdfConverter::GetPageCallback& get_page_callback);
- void Stop();
- // UtilityProcessHostClient implementation.
- void OnProcessCrashed(int exit_code) override;
- void OnProcessLaunchFailed(int exit_code) override;
- // Needs to be public to handle ChromeUtilityHostMsg_PreCacheFontCharacters
- // sync message replies.
- bool Send(IPC::Message* msg);
- protected:
- class GetPageCallbackData {
- public:
- GetPageCallbackData(int page_number, PdfConverter::GetPageCallback callback)
- : page_number_(page_number), callback_(callback) {}
- GetPageCallbackData(GetPageCallbackData&& other) {
- *this = std::move(other);
- }
- GetPageCallbackData& operator=(GetPageCallbackData&& rhs) {
- page_number_ = rhs.page_number_;
- callback_ = rhs.callback_;
- file_ = std::move(rhs.file_);
- return *this;
- }
- int page_number() const { return page_number_; }
- const PdfConverter::GetPageCallback& callback() const { return callback_; }
- ScopedTempFile TakeFile() { return std::move(file_); }
- void set_file(ScopedTempFile file) { file_ = std::move(file); }
- private:
- int page_number_;
- PdfConverter::GetPageCallback callback_;
- ScopedTempFile file_;
- DISALLOW_COPY_AND_ASSIGN(GetPageCallbackData);
- };
- ~PdfConverterUtilityProcessHostClient() override;
- bool OnMessageReceived(const IPC::Message& message) override;
- // Helper functions: must be overridden by subclasses
- // Set the process name
- virtual base::string16 GetName() const;
- // Create a metafileplayer subclass file from a temporary file.
- virtual std::unique_ptr<MetafilePlayer> GetFileFromTemp(
- std::unique_ptr<base::File, content::BrowserThread::DeleteOnFileThread>
- temp_file);
- // Send the messages to Start, GetPage, and Stop.
- virtual void SendStartMessage(IPC::PlatformFileForTransit transit);
- virtual void SendGetPageMessage(int page_number,
- IPC::PlatformFileForTransit transit);
- virtual void SendStopMessage();
- // Message handlers:
- void OnPageCount(int page_count);
- void OnPageDone(bool success, float scale_factor);
- void OnFailed();
- void OnTempPdfReady(ScopedTempFile pdf);
- void OnTempFileReady(GetPageCallbackData* callback_data,
- ScopedTempFile temp_file);
- // Additional message handler needed for Pdf to Emf
- void OnPreCacheFontCharacters(const LOGFONT& log_font,
- const base::string16& characters);
- scoped_refptr<RefCountedTempDir> temp_dir_;
- // Used to suppress callbacks after PdfConverter is deleted.
- base::WeakPtr<PdfConverterImpl> converter_;
- PdfRenderSettings settings_;
- // Document loaded callback.
- PdfConverter::StartCallback start_callback_;
- // Process host for IPC.
- base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
- // Queue of callbacks for GetPage() requests. Utility process should reply
- // with PageDone in the same order as requests were received.
- // Use containers that keeps element pointers valid after push() and pop().
- using GetPageCallbacks = std::queue<GetPageCallbackData>;
- GetPageCallbacks get_page_callbacks_;
- DISALLOW_COPY_AND_ASSIGN(PdfConverterUtilityProcessHostClient);
- };
- std::unique_ptr<MetafilePlayer>
- PdfConverterUtilityProcessHostClient::GetFileFromTemp(
- std::unique_ptr<base::File, content::BrowserThread::DeleteOnFileThread>
- temp_file) {
- if (settings_.mode == PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2 ||
- settings_.mode == PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3) {
- return std::make_unique<PostScriptMetaFile>(temp_dir_,
- std::move(temp_file));
- }
- return std::make_unique<LazyEmf>(temp_dir_, std::move(temp_file));
- }
- class PdfConverterImpl : public PdfConverter {
- public:
- PdfConverterImpl();
- ~PdfConverterImpl() override;
- base::WeakPtr<PdfConverterImpl> GetWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
- }
- void Start(const scoped_refptr<base::RefCountedMemory>& data,
- const PdfRenderSettings& conversion_settings,
- const StartCallback& start_callback);
- void GetPage(int page_number,
- const GetPageCallback& get_page_callback) override;
- // Helps to cancel callbacks if this object is destroyed.
- void RunCallback(const base::Closure& callback);
- void Start(
- const scoped_refptr<PdfConverterUtilityProcessHostClient>& utility_client,
- const scoped_refptr<base::RefCountedMemory>& data,
- const StartCallback& start_callback);
- private:
- scoped_refptr<PdfConverterUtilityProcessHostClient> utility_client_;
- base::WeakPtrFactory<PdfConverterImpl> weak_ptr_factory_;
- DISALLOW_COPY_AND_ASSIGN(PdfConverterImpl);
- };
- ScopedTempFile CreateTempFile(scoped_refptr<RefCountedTempDir>* temp_dir) {
- if (!temp_dir->get())
- *temp_dir = new RefCountedTempDir();
- ScopedTempFile file;
- if (!(*temp_dir)->IsValid())
- return file;
- base::FilePath path;
- if (!base::CreateTemporaryFileInDir((*temp_dir)->GetPath(), &path)) {
- PLOG(ERROR) << "Failed to create file in "
- << (*temp_dir)->GetPath().value();
- return file;
- }
- file.reset(new base::File(
- path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
- base::File::FLAG_READ | base::File::FLAG_DELETE_ON_CLOSE |
- base::File::FLAG_TEMPORARY));
- if (!file->IsValid()) {
- PLOG(ERROR) << "Failed to create " << path.value();
- file.reset();
- }
- return file;
- }
- ScopedTempFile CreateTempPdfFile(
- const scoped_refptr<base::RefCountedMemory>& data,
- scoped_refptr<RefCountedTempDir>* temp_dir) {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- ScopedTempFile pdf_file = CreateTempFile(temp_dir);
- if (!pdf_file ||
- static_cast<int>(data->size()) !=
- pdf_file->WriteAtCurrentPos(data->front_as<char>(), data->size())) {
- pdf_file.reset();
- return pdf_file;
- }
- pdf_file->Seek(base::File::FROM_BEGIN, 0);
- return pdf_file;
- }
- bool LazyEmf::SafePlayback(HDC hdc) const {
- Emf emf;
- bool result = LoadEmf(&emf) && emf.SafePlayback(hdc);
- // TODO(thestig): Fix destruction of metafiles. For some reasons
- // instances of Emf are not deleted. https://crbug.com/260806
- // It's known that the Emf going to be played just once to a printer. So just
- // release |file_| here.
- Close();
- return result;
- }
- bool LazyEmf::GetDataAsVector(std::vector<char>* buffer) const {
- NOTREACHED();
- return false;
- }
- bool LazyEmf::SaveTo(base::File* file) const {
- Emf emf;
- return LoadEmf(&emf) && emf.SaveTo(file);
- }
- void LazyEmf::Close() const {
- file_.reset();
- temp_dir_ = nullptr;
- }
- bool LazyEmf::LoadEmf(Emf* emf) const {
- file_->Seek(base::File::FROM_BEGIN, 0);
- int64_t size = file_->GetLength();
- if (size <= 0)
- return false;
- std::vector<char> data(size);
- if (file_->ReadAtCurrentPos(data.data(), data.size()) != size)
- return false;
- return emf->InitFromData(data.data(), data.size());
- }
- PostScriptMetaFile::~PostScriptMetaFile() {}
- bool PostScriptMetaFile::SafePlayback(HDC hdc) const {
- // TODO(thestig): Fix destruction of metafiles. For some reasons
- // instances of Emf are not deleted. https://crbug.com/260806
- // It's known that the Emf going to be played just once to a printer. So just
- // release |file_| before returning.
- Emf emf;
- if (!LoadEmf(&emf)) {
- Close();
- return false;
- }
- {
- // Ensure enumerator destruction before calling Close() below.
- Emf::Enumerator emf_enum(emf, nullptr, nullptr);
- for (const Emf::Record& record : emf_enum) {
- auto* emf_record = record.record();
- if (emf_record->iType != EMR_GDICOMMENT)
- continue;
- const EMRGDICOMMENT* comment =
- reinterpret_cast<const EMRGDICOMMENT*>(emf_record);
- const char* data = reinterpret_cast<const char*>(comment->Data);
- const uint16_t* ptr = reinterpret_cast<const uint16_t*>(data);
- int ret = ExtEscape(hdc, PASSTHROUGH, 2 + *ptr, data, 0, nullptr);
- DCHECK_EQ(*ptr, ret);
- }
- }
- Close();
- return true;
- }
- PdfConverterUtilityProcessHostClient::PdfConverterUtilityProcessHostClient(
- base::WeakPtr<PdfConverterImpl> converter,
- const PdfRenderSettings& settings)
- : converter_(converter), settings_(settings) {}
- PdfConverterUtilityProcessHostClient::~PdfConverterUtilityProcessHostClient() {}
- void PdfConverterUtilityProcessHostClient::Start(
- const scoped_refptr<base::RefCountedMemory>& data,
- const PdfConverter::StartCallback& start_callback) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&PdfConverterUtilityProcessHostClient::Start, this, data,
- start_callback));
- return;
- }
- // Store callback before any OnFailed() call to make it called on failure.
- start_callback_ = start_callback;
- // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load
- // gdiplus.dll, change how rendering happens, and not be able to correctly
- // generate when sent to a metafile DC.
- utility_process_host_ = content::UtilityProcessHost::Create(
- this, base::ThreadTaskRunnerHandle::Get())
- ->AsWeakPtr();
- utility_process_host_->SetName(GetName());
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&CreateTempPdfFile, data, &temp_dir_),
- base::Bind(&PdfConverterUtilityProcessHostClient::OnTempPdfReady, this));
- }
- void PdfConverterUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!utility_process_host_ || !pdf)
- return OnFailed();
- // Should reply with OnPageCount().
- SendStartMessage(
- IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false));
- }
- void PdfConverterUtilityProcessHostClient::OnPageCount(int page_count) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (start_callback_.is_null())
- return OnFailed();
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&PdfConverterImpl::RunCallback, converter_,
- base::Bind(start_callback_, page_count)));
- start_callback_.Reset();
- }
- void PdfConverterUtilityProcessHostClient::GetPage(
- int page_number,
- const PdfConverter::GetPageCallback& get_page_callback) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&PdfConverterUtilityProcessHostClient::GetPage, this,
- page_number, get_page_callback));
- return;
- }
- // Store callback before any OnFailed() call to make it called on failure.
- get_page_callbacks_.push(GetPageCallbackData(page_number, get_page_callback));
- if (!utility_process_host_)
- return OnFailed();
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::FILE, FROM_HERE, base::Bind(&CreateTempFile, &temp_dir_),
- base::Bind(&PdfConverterUtilityProcessHostClient::OnTempFileReady, this,
- &get_page_callbacks_.back()));
- }
- void PdfConverterUtilityProcessHostClient::OnTempFileReady(
- GetPageCallbackData* callback_data,
- ScopedTempFile temp_file) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!utility_process_host_ || !temp_file)
- return OnFailed();
- IPC::PlatformFileForTransit transit =
- IPC::GetPlatformFileForTransit(temp_file->GetPlatformFile(), false);
- callback_data->set_file(std::move(temp_file));
- // Should reply with OnPageDone().
- SendGetPageMessage(callback_data->page_number(), transit);
- }
- void PdfConverterUtilityProcessHostClient::OnPageDone(bool success,
- float scale_factor) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (get_page_callbacks_.empty())
- return OnFailed();
- GetPageCallbackData& data = get_page_callbacks_.front();
- std::unique_ptr<MetafilePlayer> file;
- if (success) {
- ScopedTempFile temp_file = data.TakeFile();
- if (!temp_file) // Unexpected message from utility process.
- return OnFailed();
- file = GetFileFromTemp(std::move(temp_file));
- }
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&PdfConverterImpl::RunCallback, converter_,
- base::Bind(data.callback(), data.page_number(), scale_factor,
- base::Passed(&file))));
- get_page_callbacks_.pop();
- }
- void PdfConverterUtilityProcessHostClient::Stop() {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&PdfConverterUtilityProcessHostClient::Stop, this));
- return;
- }
- SendStopMessage();
- }
- void PdfConverterUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
- OnFailed();
- }
- void PdfConverterUtilityProcessHostClient::OnProcessLaunchFailed(
- int exit_code) {
- OnFailed();
- }
- bool PdfConverterUtilityProcessHostClient::Send(IPC::Message* msg) {
- if (utility_process_host_)
- return utility_process_host_->Send(msg);
- delete msg;
- return false;
- }
- void PdfConverterUtilityProcessHostClient::OnFailed() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!start_callback_.is_null())
- OnPageCount(0);
- while (!get_page_callbacks_.empty())
- OnPageDone(false, 0.0f);
- utility_process_host_.reset();
- }
- void PdfConverterUtilityProcessHostClient::OnPreCacheFontCharacters(
- const LOGFONT& font,
- const base::string16& str) {
- // TODO(scottmg): pdf/ppapi still require the renderer to be able to precache
- // GDI fonts (http://crbug.com/383227), even when using DirectWrite.
- // Eventually this shouldn't be added and should be moved to
- // FontCacheDispatcher too. http://crbug.com/356346.
- // First, comments from FontCacheDispatcher::OnPreCacheFont do apply here too.
- // Except that for True Type fonts,
- // GetTextMetrics will not load the font in memory.
- // The only way windows seem to load properly, it is to create a similar
- // device (like the one in which we print), then do an ExtTextOut,
- // as we do in the printing thread, which is sandboxed.
- HDC hdc = CreateEnhMetaFile(nullptr, nullptr, nullptr, nullptr);
- HFONT font_handle = CreateFontIndirect(&font);
- DCHECK(font_handle != nullptr);
- HGDIOBJ old_font = SelectObject(hdc, font_handle);
- DCHECK(old_font != nullptr);
- ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, str.c_str(), str.length(), nullptr);
- SelectObject(hdc, old_font);
- DeleteObject(font_handle);
- HENHMETAFILE metafile = CloseEnhMetaFile(hdc);
- if (metafile)
- DeleteEnhMetaFile(metafile);
- }
- bool PdfConverterUtilityProcessHostClient::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PdfConverterUtilityProcessHostClient, message)
- IPC_MESSAGE_HANDLER(
- ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount)
- IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone,
- OnPageDone)
- IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PreCacheFontCharacters,
- OnPreCacheFontCharacters)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
- }
- base::string16 PdfConverterUtilityProcessHostClient::GetName() const {
- return L"ChromeUtilityProcessPDFConvertor";
- }
- void PdfConverterUtilityProcessHostClient::SendGetPageMessage(
- int page_number,
- IPC::PlatformFileForTransit transit) {
- Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage(page_number,
- transit));
- }
- void PdfConverterUtilityProcessHostClient::SendStartMessage(
- IPC::PlatformFileForTransit transit) {
- Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(transit, settings_));
- }
- void PdfConverterUtilityProcessHostClient::SendStopMessage() {
- Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop());
- }
- // Pdf Converter Impl and subclasses
- PdfConverterImpl::PdfConverterImpl() : weak_ptr_factory_(this) {}
- PdfConverterImpl::~PdfConverterImpl() {
- if (utility_client_.get())
- utility_client_->Stop();
- }
- void PdfConverterImpl::Start(
- const scoped_refptr<PdfConverterUtilityProcessHostClient>& utility_client,
- const scoped_refptr<base::RefCountedMemory>& data,
- const StartCallback& start_callback) {
- DCHECK(!utility_client_);
- utility_client_ = utility_client;
- utility_client_->Start(data, start_callback);
- }
- void PdfConverterImpl::GetPage(int page_number,
- const GetPageCallback& get_page_callback) {
- utility_client_->GetPage(page_number, get_page_callback);
- }
- void PdfConverterImpl::RunCallback(const base::Closure& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- callback.Run();
- }
- } // namespace
- PdfConverter::~PdfConverter() {}
- // static
- std::unique_ptr<PdfConverter> PdfConverter::StartPdfConverter(
- const scoped_refptr<base::RefCountedMemory>& data,
- const PdfRenderSettings& conversion_settings,
- const StartCallback& start_callback) {
- std::unique_ptr<PdfConverterImpl> converter =
- std::make_unique<PdfConverterImpl>();
- converter->Start(new PdfConverterUtilityProcessHostClient(
- converter->GetWeakPtr(), conversion_settings),
- data, start_callback);
- return std::move(converter);
- }
- } // namespace printing
|