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

Unified Diff: chrome/browser/printing/pdf_to_emf_converter.cc

Issue 566693002: Use file handles to interact with utility process. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Wed Sep 17 10:40:51 PDT 2014 Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/printing/pdf_to_emf_converter.h ('k') | chrome/browser/printing/print_job.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/printing/pdf_to_emf_converter.cc
diff --git a/chrome/browser/printing/pdf_to_emf_converter.cc b/chrome/browser/printing/pdf_to_emf_converter.cc
index f0a8bab029aa923a92c9ca5788a0843d595a18ab..39259365ecb21b9e1539c0a171d658366031d7a0 100644
--- a/chrome/browser/printing/pdf_to_emf_converter.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/printing/pdf_to_emf_converter.h"
-#include "base/bind_helpers.h"
-#include "base/cancelable_callback.h"
+#include <queue>
+
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
@@ -17,7 +17,6 @@
#include "content/public/browser/utility_process_host.h"
#include "content/public/browser/utility_process_host_client.h"
#include "printing/emf_win.h"
-#include "printing/page_range.h"
#include "printing/pdf_render_settings.h"
namespace printing {
@@ -26,319 +25,469 @@ namespace {
using content::BrowserThread;
-class FileHandlers
- : public base::RefCountedThreadSafe<FileHandlers,
+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:
- FileHandlers() {}
-
- void Init(base::RefCountedMemory* data);
- bool IsValid();
-
- base::FilePath GetEmfPath() const {
- return temp_dir_.path().AppendASCII("output.emf");
- }
-
- base::FilePath GetEmfPagePath(int page_number) const {
- return GetEmfPath().InsertBeforeExtensionASCII(
- base::StringPrintf(".%d", page_number));
- }
-
- base::FilePath GetPdfPath() const {
- return temp_dir_.path().AppendASCII("input.pdf");
- }
-
- IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) {
- DCHECK(pdf_file_.IsValid());
- IPC::PlatformFileForTransit transit =
- IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process);
- return transit;
- }
-
- const base::FilePath& GetBasePath() const {
- return temp_dir_.path();
- }
+ RefCountedTempDir() { 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<FileHandlers>;
-
- ~FileHandlers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); }
+ friend class base::DeleteHelper<RefCountedTempDir>;
+ ~RefCountedTempDir() {};
base::ScopedTempDir temp_dir_;
- base::File pdf_file_;
+ DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir);
};
-void FileHandlers::Init(base::RefCountedMemory* data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+typedef scoped_ptr<base::File, BrowserThread::DeleteOnFileThread>
+ ScopedTempFile;
- if (!temp_dir_.CreateUniqueTempDir()) {
- return;
- }
+// 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(); }
- pdf_file_.Initialize(GetPdfPath(),
- base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
- base::File::FLAG_READ |
- base::File::FLAG_DELETE_ON_CLOSE);
- if (static_cast<int>(data->size()) !=
- pdf_file_.WriteAtCurrentPos(data->front_as<char>(), data->size())) {
- pdf_file_.Close();
- return;
- }
- pdf_file_.Seek(base::File::FROM_BEGIN, 0);
- pdf_file_.Flush();
-}
+ virtual bool SafePlayback(HDC hdc) const OVERRIDE;
+ virtual bool SaveTo(base::File* file) const OVERRIDE;
-bool FileHandlers::IsValid() {
- return pdf_file_.IsValid();
-}
+ private:
+ void Close() const;
+ bool LoadEmf(Emf* emf) const;
-// Modification of Emf to keep references to |FileHandlers|.
-// |FileHandlers| must be deleted after the last metafile is closed because
-// Emf holds files locked.
-// Ideally we want to use FLAG_DELETE_ON_CLOSE, but it requires large changes.
-// It's going to be done for crbug.com/408184
-class TempEmf : public Emf {
- public:
- explicit TempEmf(const scoped_refptr<FileHandlers>& files) : files_(files) {}
- virtual ~TempEmf() {}
-
- virtual bool SafePlayback(HDC hdc) const OVERRIDE {
- bool result = Emf::SafePlayback(hdc);
- TempEmf* this_mutable = const_cast<TempEmf*>(this);
- // TODO(vitalybuka): Fix destruction of metafiles. For some reasons
- // instances of Emf are not deleted. crbug.com/411683
- // |files_| must be released as soon as possible to guarantee deletion.
- // It's know that this Emf file is going to be played just once to
- // a printer. So just release files here.
- this_mutable->Close();
- this_mutable->files_ = NULL;
- return result;
- }
+ mutable scoped_refptr<RefCountedTempDir> temp_dir_;
+ mutable ScopedTempFile file_; // Mutable because of consts in base class.
- private:
- scoped_refptr<FileHandlers> files_;
- DISALLOW_COPY_AND_ASSIGN(TempEmf);
+ 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 file on the FILE thread.
+// 2. Create pdf file on the FILE thread.
// 3. Start utility process and start conversion on the IO thread.
-// 4. Run result callback on the UI thread.
-// 5. Instance is destroyed from any thread that has the last reference.
-// 6. FileHandlers destroyed on the FILE thread.
-// This step posts |FileHandlers| to be destroyed on the FILE 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:
- explicit PdfToEmfUtilityProcessHostClient(
- const printing::PdfRenderSettings& settings);
+ 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 Convert(base::RefCountedMemory* data,
- const PdfToEmfConverter::ResultCallback& 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 OnSucceeded(const std::vector<printing::PageRange>& page_ranges,
- double scale_factor);
+ void OnPageCount(int page_count);
+ void OnPageDone(bool success, double scale_factor);
+
void OnFailed();
+ void OnTempPdfReady(ScopedTempFile pdf);
+ void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf);
- void RunCallback(const std::vector<printing::PageRange>& page_ranges,
- double scale_factor);
+ scoped_refptr<RefCountedTempDir> temp_dir_;
- void StartProcessOnIOThread();
+ // Used to suppress callbacks after PdfToEmfConverterImpl is deleted.
+ base::WeakPtr<PdfToEmfConverterImpl> converter_;
+ PdfRenderSettings settings_;
+ scoped_refptr<base::RefCountedMemory> data_;
- void RunCallbackOnUIThread(
- const std::vector<printing::PageRange>& page_ranges,
- double scale_factor);
- void OnFilesReadyOnUIThread();
+ // Document loaded callback.
+ PdfToEmfConverter::StartCallback start_callback_;
- scoped_refptr<FileHandlers> files_;
- printing::PdfRenderSettings settings_;
- PdfToEmfConverter::ResultCallback 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);
};
-PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
- const printing::PdfRenderSettings& settings)
- : settings_(settings) {}
+class PdfToEmfConverterImpl : public PdfToEmfConverter {
+ public:
+ PdfToEmfConverterImpl();
-PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
+ 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))
+ *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();
}
-void PdfToEmfUtilityProcessHostClient::Convert(
- base::RefCountedMemory* data,
- const PdfToEmfConverter::ResultCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- callback_ = callback;
- CHECK(!files_.get());
- files_ = new FileHandlers();
- BrowserThread::PostTaskAndReply(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)),
- base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread,
- this));
+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();
}
-void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
- OnFailed();
+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 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_Succeeded, OnSucceeded)
- IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed,
- OnFailed)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
+bool LazyEmf::SaveTo(base::File* file) const {
+ Emf emf;
+ return LoadEmf(&emf) && emf.SaveTo(file);
}
-void PdfToEmfUtilityProcessHostClient::OnProcessStarted() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!utility_process_host_) {
- RunCallbackOnUIThread(std::vector<printing::PageRange>(), 0.0);
- return;
- }
+void LazyEmf::Close() const {
+ file_.reset();
+ temp_dir_ = NULL;
+}
- base::ProcessHandle process = utility_process_host_->GetData().handle;
- utility_process_host_->Send(
- new ChromeUtilityMsg_RenderPDFPagesToMetafiles(
- files_->GetPdfForProcess(process),
- files_->GetEmfPath(),
- settings_,
- std::vector<printing::PageRange>()));
- utility_process_host_.reset();
+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());
}
-void PdfToEmfUtilityProcessHostClient::OnSucceeded(
- const std::vector<printing::PageRange>& page_ranges,
- double scale_factor) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- RunCallback(page_ranges, scale_factor);
+PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
+ base::WeakPtr<PdfToEmfConverterImpl> converter,
+ const PdfRenderSettings& settings)
+ : converter_(converter), settings_(settings) {
}
-void PdfToEmfUtilityProcessHostClient::OnFailed() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- RunCallback(std::vector<printing::PageRange>(), 0.0);
+PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
}
-void PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!files_->IsValid()) {
- RunCallbackOnUIThread(std::vector<printing::PageRange>(), 0.0);
+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;
}
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&PdfToEmfUtilityProcessHostClient::StartProcessOnIOThread,
- this));
-}
+ data_ = data;
+
+ // Store callback before any OnFailed() call to make it called on failure.
+ start_callback_ = start_callback;
-void PdfToEmfUtilityProcessHostClient::StartProcessOnIOThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- utility_process_host_ =
- content::UtilityProcessHost::Create(
- this,
- base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr();
// 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_->SetExposedDir(files_->GetBasePath());
- utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
+ 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::RunCallback(
- const std::vector<printing::PageRange>& page_ranges,
- double scale_factor) {
- BrowserThread::PostTask(
- BrowserThread::UI,
+void PdfToEmfUtilityProcessHostClient::OnProcessStarted() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!utility_process_host_)
+ return OnFailed();
+
+ base::ProcessHandle process = utility_process_host_->GetData().handle;
+ scoped_refptr<base::RefCountedMemory> data = data_;
+ data_ = NULL;
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::FILE,
FROM_HERE,
- base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread,
- this,
- page_ranges,
- scale_factor));
+ base::Bind(&CreateTempPdfFile, data, &temp_dir_),
+ base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this));
}
-void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread(
- const std::vector<printing::PageRange>& page_ranges,
- double scale_factor) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- ScopedVector<MetafilePlayer> pages;
- std::vector<printing::PageRange>::const_iterator iter;
- for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) {
- for (int page_number = iter->from; page_number <= iter->to; ++page_number) {
- scoped_ptr<TempEmf> metafile(new TempEmf(files_));
- if (!metafile->InitFromFile(files_->GetEmfPagePath(page_number))) {
- NOTREACHED() << "Invalid metafile";
- metafile.reset();
- }
- pages.push_back(metafile.release());
- }
+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;
}
- files_ = NULL;
- if (!callback_.is_null()) {
- callback_.Run(scale_factor, &pages);
- callback_.Reset();
+
+ // 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,
+ double scale_factor) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (get_page_callbacks_.empty())
+ return OnFailed();
+ scoped_ptr<LazyEmf> 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());
}
-class PdfToEmfConverterImpl : public PdfToEmfConverter {
- public:
- PdfToEmfConverterImpl();
+void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
+ OnFailed();
+}
- virtual ~PdfToEmfConverterImpl();
+void PdfToEmfUtilityProcessHostClient::OnProcessLaunchFailed() {
+ OnFailed();
+}
- virtual void Start(base::RefCountedMemory* data,
- const printing::PdfRenderSettings& conversion_settings,
- const ResultCallback& callback) OVERRIDE;
+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;
+}
- private:
- scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_;
- base::CancelableCallback<ResultCallback::RunType> callback_;
+bool PdfToEmfUtilityProcessHostClient::Send(IPC::Message* msg) {
+ if (utility_process_host_)
+ return utility_process_host_->Send(msg);
+ delete msg;
+ return false;
+}
- DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl);
-};
+void PdfToEmfUtilityProcessHostClient::OnFailed() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!start_callback_.is_null())
+ OnPageCount(0);
+ while (!get_page_callbacks_.empty())
+ OnPageDone(false, 0.0);
+ utility_process_host_.reset();
+}
-PdfToEmfConverterImpl::PdfToEmfConverterImpl() {
+PdfToEmfConverterImpl::PdfToEmfConverterImpl() : weak_ptr_factory_(this) {
}
PdfToEmfConverterImpl::~PdfToEmfConverterImpl() {
+ if (utility_client_)
+ utility_client_->Stop();
}
void PdfToEmfConverterImpl::Start(
- base::RefCountedMemory* data,
- const printing::PdfRenderSettings& conversion_settings,
- const ResultCallback& callback) {
- // Rebind cancelable callback to avoid calling callback if
- // PdfToEmfConverterImpl is destroyed.
- callback_.Reset(callback);
- utility_client_ = new PdfToEmfUtilityProcessHostClient(conversion_settings);
- utility_client_->Convert(data, callback_.callback());
+ const scoped_refptr<base::RefCountedMemory>& data,
+ const PdfRenderSettings& conversion_settings,
+ const StartCallback& start_callback) {
+ DCHECK(!utility_client_);
+ 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());
« no previous file with comments | « chrome/browser/printing/pdf_to_emf_converter.h ('k') | chrome/browser/printing/print_job.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698