|
@@ -0,0 +1,495 @@
|
|
|
+// 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 <queue>
|
|
|
+
|
|
|
+#include "base/files/file.h"
|
|
|
+#include "base/files/file_util.h"
|
|
|
+#include "base/files/scoped_temp_dir.h"
|
|
|
+#include "base/logging.h"
|
|
|
+#include "chrome/common/chrome_utility_messages.h"
|
|
|
+#include "chrome/common/print_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"
|
|
|
+
|
|
|
+namespace printing {
|
|
|
+
|
|
|
+namespace {
|
|
|
+
|
|
|
+using content::BrowserThread;
|
|
|
+
|
|
|
+class PdfToEmfConverterImpl;
|
|
|
+
|
|
|
+// 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_.path(); }
|
|
|
+
|
|
|
+ private:
|
|
|
+ friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
|
|
|
+ friend class base::DeleteHelper<RefCountedTempDir>;
|
|
|
+ ~RefCountedTempDir() {}
|
|
|
+
|
|
|
+ base::ScopedTempDir temp_dir_;
|
|
|
+ DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir);
|
|
|
+};
|
|
|
+
|
|
|
+typedef scoped_ptr<base::File, BrowserThread::DeleteOnFileThread>
|
|
|
+ ScopedTempFile;
|
|
|
+
|
|
|
+// 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_(file.Pass()) {}
|
|
|
+ virtual ~LazyEmf() { Close(); }
|
|
|
+
|
|
|
+ virtual bool SafePlayback(HDC hdc) const override;
|
|
|
+ virtual bool SaveTo(base::File* file) const override;
|
|
|
+
|
|
|
+ private:
|
|
|
+ void Close() const;
|
|
|
+ bool LoadEmf(Emf* emf) const;
|
|
|
+
|
|
|
+ mutable scoped_refptr<RefCountedTempDir> temp_dir_;
|
|
|
+ mutable ScopedTempFile file_; // Mutable because of consts in base class.
|
|
|
+
|
|
|
+ DISALLOW_COPY_AND_ASSIGN(LazyEmf);
|
|
|
+};
|
|
|
+
|
|
|
+// Converts PDF into EMF.
|
|
|
+// 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 PdfToEmfUtilityProcessHostClient
|
|
|
+ : public content::UtilityProcessHostClient {
|
|
|
+ public:
|
|
|
+ PdfToEmfUtilityProcessHostClient(
|
|
|
+ base::WeakPtr<PdfToEmfConverterImpl> converter,
|
|
|
+ const PdfRenderSettings& settings);
|
|
|
+
|
|
|
+ void Start(const scoped_refptr<base::RefCountedMemory>& data,
|
|
|
+ const PdfToEmfConverter::StartCallback& start_callback);
|
|
|
+
|
|
|
+ void GetPage(int page_number,
|
|
|
+ const PdfToEmfConverter::GetPageCallback& get_page_callback);
|
|
|
+
|
|
|
+ void Stop();
|
|
|
+
|
|
|
+ // UtilityProcessHostClient implementation.
|
|
|
+ virtual void OnProcessCrashed(int exit_code) override;
|
|
|
+ virtual void OnProcessLaunchFailed() override;
|
|
|
+ virtual bool OnMessageReceived(const IPC::Message& message) override;
|
|
|
+
|
|
|
+ private:
|
|
|
+ class GetPageCallbackData {
|
|
|
+ MOVE_ONLY_TYPE_FOR_CPP_03(GetPageCallbackData, RValue);
|
|
|
+
|
|
|
+ public:
|
|
|
+ GetPageCallbackData(int page_number,
|
|
|
+ PdfToEmfConverter::GetPageCallback callback)
|
|
|
+ : page_number_(page_number), callback_(callback) {}
|
|
|
+
|
|
|
+ // Move constructor for STL.
|
|
|
+ GetPageCallbackData(RValue other) { this->operator=(other); }
|
|
|
+
|
|
|
+ // Move assignment for STL.
|
|
|
+ GetPageCallbackData& operator=(RValue rhs) {
|
|
|
+ page_number_ = rhs.object->page_number_;
|
|
|
+ callback_ = rhs.object->callback_;
|
|
|
+ emf_ = rhs.object->emf_.Pass();
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+
|
|
|
+ int page_number() const { return page_number_; }
|
|
|
+ const PdfToEmfConverter::GetPageCallback& callback() const {
|
|
|
+ return callback_;
|
|
|
+ }
|
|
|
+ ScopedTempFile emf() { return emf_.Pass(); }
|
|
|
+ void set_emf(ScopedTempFile emf) { emf_ = emf.Pass(); }
|
|
|
+
|
|
|
+ private:
|
|
|
+ int page_number_;
|
|
|
+ PdfToEmfConverter::GetPageCallback callback_;
|
|
|
+ ScopedTempFile emf_;
|
|
|
+ };
|
|
|
+
|
|
|
+ virtual ~PdfToEmfUtilityProcessHostClient();
|
|
|
+
|
|
|
+ bool Send(IPC::Message* msg);
|
|
|
+
|
|
|
+ // Message handlers.
|
|
|
+ void OnProcessStarted();
|
|
|
+ void OnPageCount(int page_count);
|
|
|
+ void OnPageDone(bool success, float scale_factor);
|
|
|
+
|
|
|
+ void OnFailed();
|
|
|
+ void OnTempPdfReady(ScopedTempFile pdf);
|
|
|
+ void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf);
|
|
|
+
|
|
|
+ scoped_refptr<RefCountedTempDir> temp_dir_;
|
|
|
+
|
|
|
+ // Used to suppress callbacks after PdfToEmfConverterImpl is deleted.
|
|
|
+ base::WeakPtr<PdfToEmfConverterImpl> converter_;
|
|
|
+ PdfRenderSettings settings_;
|
|
|
+ scoped_refptr<base::RefCountedMemory> data_;
|
|
|
+
|
|
|
+ // Document loaded callback.
|
|
|
+ PdfToEmfConverter::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().
|
|
|
+ typedef std::queue<GetPageCallbackData> GetPageCallbacks;
|
|
|
+ GetPageCallbacks get_page_callbacks_;
|
|
|
+
|
|
|
+ DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient);
|
|
|
+};
|
|
|
+
|
|
|
+class PdfToEmfConverterImpl : public PdfToEmfConverter {
|
|
|
+ public:
|
|
|
+ PdfToEmfConverterImpl();
|
|
|
+
|
|
|
+ virtual ~PdfToEmfConverterImpl();
|
|
|
+
|
|
|
+ virtual void Start(const scoped_refptr<base::RefCountedMemory>& data,
|
|
|
+ const PdfRenderSettings& conversion_settings,
|
|
|
+ const StartCallback& start_callback) override;
|
|
|
+
|
|
|
+ virtual 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);
|
|
|
+
|
|
|
+ private:
|
|
|
+ scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_;
|
|
|
+ base::WeakPtrFactory<PdfToEmfConverterImpl> weak_ptr_factory_;
|
|
|
+
|
|
|
+ DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl);
|
|
|
+};
|
|
|
+
|
|
|
+ScopedTempFile CreateTempFile(scoped_refptr<RefCountedTempDir>* temp_dir) {
|
|
|
+ if (!temp_dir->get())
|
|
|
+ *temp_dir = new RefCountedTempDir();
|
|
|
+ ScopedTempFile file;
|
|
|
+ if (!(*temp_dir)->IsValid())
|
|
|
+ return file.Pass();
|
|
|
+ base::FilePath path;
|
|
|
+ if (!base::CreateTemporaryFileInDir((*temp_dir)->GetPath(), &path))
|
|
|
+ return file.Pass();
|
|
|
+ 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())
|
|
|
+ file.reset();
|
|
|
+ return file.Pass();
|
|
|
+}
|
|
|
+
|
|
|
+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();
|
|
|
+ }
|
|
|
+ pdf_file->Seek(base::File::FROM_BEGIN, 0);
|
|
|
+ return pdf_file.Pass();
|
|
|
+}
|
|
|
+
|
|
|
+bool LazyEmf::SafePlayback(HDC hdc) const {
|
|
|
+ Emf emf;
|
|
|
+ bool result = LoadEmf(&emf) && emf.SafePlayback(hdc);
|
|
|
+ // TODO(vitalybuka): Fix destruction of metafiles. For some reasons
|
|
|
+ // instances of Emf are not deleted. crbug.com/411683
|
|
|
+ // 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::SaveTo(base::File* file) const {
|
|
|
+ Emf emf;
|
|
|
+ return LoadEmf(&emf) && emf.SaveTo(file);
|
|
|
+}
|
|
|
+
|
|
|
+void LazyEmf::Close() const {
|
|
|
+ file_.reset();
|
|
|
+ temp_dir_ = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+bool LazyEmf::LoadEmf(Emf* emf) const {
|
|
|
+ file_->Seek(base::File::FROM_BEGIN, 0);
|
|
|
+ int64 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());
|
|
|
+}
|
|
|
+
|
|
|
+PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
|
|
|
+ base::WeakPtr<PdfToEmfConverterImpl> converter,
|
|
|
+ const PdfRenderSettings& settings)
|
|
|
+ : converter_(converter), settings_(settings) {
|
|
|
+}
|
|
|
+
|
|
|
+PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::Start(
|
|
|
+ const scoped_refptr<base::RefCountedMemory>& data,
|
|
|
+ const PdfToEmfConverter::StartCallback& start_callback) {
|
|
|
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
|
|
|
+ BrowserThread::PostTask(BrowserThread::IO,
|
|
|
+ FROM_HERE,
|
|
|
+ base::Bind(&PdfToEmfUtilityProcessHostClient::Start,
|
|
|
+ this,
|
|
|
+ data,
|
|
|
+ start_callback));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ data_ = data;
|
|
|
+
|
|
|
+ // 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::MessageLoop::current()->message_loop_proxy())
|
|
|
+ ->AsWeakPtr();
|
|
|
+ if (!utility_process_host_)
|
|
|
+ return OnFailed();
|
|
|
+ // Should reply with OnProcessStarted().
|
|
|
+ Send(new ChromeUtilityMsg_StartupPing);
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::OnProcessStarted() {
|
|
|
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
+ if (!utility_process_host_)
|
|
|
+ return OnFailed();
|
|
|
+
|
|
|
+ scoped_refptr<base::RefCountedMemory> data = data_;
|
|
|
+ data_ = NULL;
|
|
|
+ BrowserThread::PostTaskAndReplyWithResult(
|
|
|
+ BrowserThread::FILE,
|
|
|
+ FROM_HERE,
|
|
|
+ base::Bind(&CreateTempPdfFile, data, &temp_dir_),
|
|
|
+ base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this));
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) {
|
|
|
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
+ if (!utility_process_host_)
|
|
|
+ return OnFailed();
|
|
|
+ base::ProcessHandle process = utility_process_host_->GetData().handle;
|
|
|
+ // Should reply with OnPageCount().
|
|
|
+ Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(
|
|
|
+ IPC::GetFileHandleForProcess(pdf->GetPlatformFile(), process, false),
|
|
|
+ settings_));
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) {
|
|
|
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
+ if (start_callback_.is_null())
|
|
|
+ return OnFailed();
|
|
|
+ BrowserThread::PostTask(BrowserThread::UI,
|
|
|
+ FROM_HERE,
|
|
|
+ base::Bind(&PdfToEmfConverterImpl::RunCallback,
|
|
|
+ converter_,
|
|
|
+ base::Bind(start_callback_, page_count)));
|
|
|
+ start_callback_.Reset();
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::GetPage(
|
|
|
+ int page_number,
|
|
|
+ const PdfToEmfConverter::GetPageCallback& get_page_callback) {
|
|
|
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
|
|
|
+ BrowserThread::PostTask(
|
|
|
+ BrowserThread::IO,
|
|
|
+ FROM_HERE,
|
|
|
+ base::Bind(&PdfToEmfUtilityProcessHostClient::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(&PdfToEmfUtilityProcessHostClient::OnTempEmfReady,
|
|
|
+ this,
|
|
|
+ &get_page_callbacks_.back()));
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::OnTempEmfReady(
|
|
|
+ GetPageCallbackData* callback_data,
|
|
|
+ ScopedTempFile emf) {
|
|
|
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
+ if (!utility_process_host_)
|
|
|
+ return OnFailed();
|
|
|
+ base::ProcessHandle process = utility_process_host_->GetData().handle;
|
|
|
+ IPC::PlatformFileForTransit transit =
|
|
|
+ IPC::GetFileHandleForProcess(emf->GetPlatformFile(), process, false);
|
|
|
+ callback_data->set_emf(emf.Pass());
|
|
|
+ // Should reply with OnPageDone().
|
|
|
+ Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage(
|
|
|
+ callback_data->page_number(), transit));
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success,
|
|
|
+ float scale_factor) {
|
|
|
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
+ if (get_page_callbacks_.empty())
|
|
|
+ return OnFailed();
|
|
|
+ scoped_ptr<MetafilePlayer> emf;
|
|
|
+ GetPageCallbackData& data = get_page_callbacks_.front();
|
|
|
+ if (success)
|
|
|
+ emf.reset(new LazyEmf(temp_dir_, data.emf().Pass()));
|
|
|
+ BrowserThread::PostTask(BrowserThread::UI,
|
|
|
+ FROM_HERE,
|
|
|
+ base::Bind(&PdfToEmfConverterImpl::RunCallback,
|
|
|
+ converter_,
|
|
|
+ base::Bind(data.callback(),
|
|
|
+ data.page_number(),
|
|
|
+ scale_factor,
|
|
|
+ base::Passed(&emf))));
|
|
|
+ get_page_callbacks_.pop();
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::Stop() {
|
|
|
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
|
|
|
+ BrowserThread::PostTask(
|
|
|
+ BrowserThread::IO,
|
|
|
+ FROM_HERE,
|
|
|
+ base::Bind(&PdfToEmfUtilityProcessHostClient::Stop, this));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop());
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
|
|
|
+ OnFailed();
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::OnProcessLaunchFailed() {
|
|
|
+ OnFailed();
|
|
|
+}
|
|
|
+
|
|
|
+bool PdfToEmfUtilityProcessHostClient::OnMessageReceived(
|
|
|
+ const IPC::Message& message) {
|
|
|
+ bool handled = true;
|
|
|
+ IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message)
|
|
|
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted)
|
|
|
+ IPC_MESSAGE_HANDLER(
|
|
|
+ ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount)
|
|
|
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone,
|
|
|
+ OnPageDone)
|
|
|
+ IPC_MESSAGE_UNHANDLED(handled = false)
|
|
|
+ IPC_END_MESSAGE_MAP()
|
|
|
+ return handled;
|
|
|
+}
|
|
|
+
|
|
|
+bool PdfToEmfUtilityProcessHostClient::Send(IPC::Message* msg) {
|
|
|
+ if (utility_process_host_)
|
|
|
+ return utility_process_host_->Send(msg);
|
|
|
+ delete msg;
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfUtilityProcessHostClient::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();
|
|
|
+}
|
|
|
+
|
|
|
+PdfToEmfConverterImpl::PdfToEmfConverterImpl() : weak_ptr_factory_(this) {
|
|
|
+}
|
|
|
+
|
|
|
+PdfToEmfConverterImpl::~PdfToEmfConverterImpl() {
|
|
|
+ if (utility_client_.get())
|
|
|
+ utility_client_->Stop();
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfConverterImpl::Start(
|
|
|
+ const scoped_refptr<base::RefCountedMemory>& data,
|
|
|
+ const PdfRenderSettings& conversion_settings,
|
|
|
+ const StartCallback& start_callback) {
|
|
|
+ DCHECK(!utility_client_.get());
|
|
|
+ utility_client_ = new PdfToEmfUtilityProcessHostClient(
|
|
|
+ weak_ptr_factory_.GetWeakPtr(), conversion_settings);
|
|
|
+ utility_client_->Start(data, start_callback);
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfConverterImpl::GetPage(int page_number,
|
|
|
+ const GetPageCallback& get_page_callback) {
|
|
|
+ utility_client_->GetPage(page_number, get_page_callback);
|
|
|
+}
|
|
|
+
|
|
|
+void PdfToEmfConverterImpl::RunCallback(const base::Closure& callback) {
|
|
|
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
+ callback.Run();
|
|
|
+}
|
|
|
+
|
|
|
+} // namespace
|
|
|
+
|
|
|
+PdfToEmfConverter::~PdfToEmfConverter() {
|
|
|
+}
|
|
|
+
|
|
|
+// static
|
|
|
+scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() {
|
|
|
+ return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl());
|
|
|
+}
|
|
|
+
|
|
|
+} // namespace printing
|