Chromium Code Reviews| 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..223019c2b0e6e088407d1a854888a7bc1ee5aae7 100644 |
| --- a/chrome/browser/printing/pdf_to_emf_converter.cc |
| +++ b/chrome/browser/printing/pdf_to_emf_converter.cc |
| @@ -4,11 +4,8 @@ |
| #include "chrome/browser/printing/pdf_to_emf_converter.h" |
| -#include "base/bind_helpers.h" |
| -#include "base/cancelable_callback.h" |
| #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/chrome_utility_printing_messages.h" |
| @@ -17,7 +14,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 +22,397 @@ namespace { |
| using content::BrowserThread; |
| -class FileHandlers |
| - : public base::RefCountedThreadSafe<FileHandlers, |
| - BrowserThread::DeleteOnFileThread> { |
| - public: |
| - FileHandlers() {} |
| - |
| - void Init(base::RefCountedMemory* data); |
| - bool IsValid(); |
| +class PdfToEmfConverterImpl; |
| - 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)); |
| - } |
| +typedef scoped_ptr<base::File, BrowserThread::DeleteOnFileThread> TempFilePtr; |
|
Lei Zhang
2014/09/16 03:36:54
Maybe rename TempFilePtr to ScopedTempFile?
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
|
| - base::FilePath GetPdfPath() const { |
| - return temp_dir_.path().AppendASCII("input.pdf"); |
| - } |
| +// Wrapper for Emf to keep only file handle in memory, and load actual data only |
| +// on playback. |InitFromFile| can play metafile directly from disk, but it |
|
Lei Zhang
2014/09/16 03:36:54
nit: |InitFromFile| -> Emf::InitFromFile()
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
|
| +// can't open file handles. We need file handles to reliably delete temporary |
| +// files, and to efficiently interact with sandbox process. |
|
Lei Zhang
2014/09/16 03:36:54
nit: sandbox -> utility?
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
|
| +class LazyEmf : public MetafilePlayer { |
| + public: |
| + explicit LazyEmf(TempFilePtr file) : file_(file.Pass()) {} |
| + virtual ~LazyEmf() { Close(); } |
| - 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(); |
| - } |
| + virtual bool SafePlayback(HDC hdc) const OVERRIDE; |
| + virtual bool SaveTo(base::File* file) const OVERRIDE; |
| private: |
| - friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>; |
| - friend class base::DeleteHelper<FileHandlers>; |
| - |
| - ~FileHandlers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); } |
| - |
| - base::ScopedTempDir temp_dir_; |
| - base::File pdf_file_; |
| -}; |
| - |
| -void FileHandlers::Init(base::RefCountedMemory* data) { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| - |
| - if (!temp_dir_.CreateUniqueTempDir()) { |
| - return; |
| - } |
| + void Close() const; |
| + bool LoadEmf(Emf* emf) const; |
| - 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(); |
| -} |
| - |
| -bool FileHandlers::IsValid() { |
| - return pdf_file_.IsValid(); |
| -} |
| - |
| -// 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; |
| - } |
| - |
| - private: |
| - scoped_refptr<FileHandlers> files_; |
| - DISALLOW_COPY_AND_ASSIGN(TempEmf); |
| + mutable TempFilePtr 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 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 requiquest page with file handle to temp file. |
|
Lei Zhang
2014/09/16 03:36:54
typo
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
|
| +// 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: |
| virtual ~PdfToEmfUtilityProcessHostClient(); |
| + bool Send(IPC::Message* msg); |
| + |
| // Message handlers. |
| void OnProcessStarted(); |
| - void OnSucceeded(const std::vector<printing::PageRange>& page_ranges, |
| - double scale_factor); |
| - void OnFailed(); |
| + void OnPageCount(int page_count); |
| + void OnPageDone(bool success, double scale_factor); |
| - void RunCallback(const std::vector<printing::PageRange>& page_ranges, |
| - double scale_factor); |
| + void OnFailed(); |
| + void OnTempPdfReady(TempFilePtr pdf); |
| + void OnTempEmfReady(int page_number, TempFilePtr emf); |
| - 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_; |
| + std::map<int, std::pair<PdfToEmfConverter::GetPageCallback, TempFilePtr> > |
|
Lei Zhang
2014/09/16 03:36:54
document what the key is.
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
|
| + 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); |
| +}; |
| + |
| +TempFilePtr CreateTempFile() { |
| + TempFilePtr file; |
| + base::FilePath path; |
| + if (!base::CreateTemporaryFile(&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(); |
| +} |
| + |
| +TempFilePtr CreateTempPdfFile( |
| + const scoped_refptr<base::RefCountedMemory>& data) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| + |
| + TempFilePtr pdf_file = CreateTempFile(); |
| + 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(); |
| +} |
| + |
| +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( |
| - const printing::PdfRenderSettings& settings) |
| - : settings_(settings) {} |
| + base::WeakPtr<PdfToEmfConverterImpl> converter, |
| + const PdfRenderSettings& settings) |
| + : converter_(converter), settings_(settings) { |
| +} |
| PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { |
| } |
| -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( |
| +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; |
| + 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(); |
| + Send(new ChromeUtilityMsg_StartupPing); |
| +} |
| + |
| +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; |
| + } |
| + |
| + bool new_request = |
| + get_page_callbacks_.insert(std::make_pair( |
| + page_number, |
| + std::make_pair(get_page_callback, |
| + TempFilePtr()))).second; |
| + DCHECK(new_request) << "Multiple requests for the same page"; |
| + if (!new_request || !utility_process_host_) |
| + return OnFailed(); |
| + |
| + BrowserThread::PostTaskAndReplyWithResult( |
| BrowserThread::FILE, |
| FROM_HERE, |
| - base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)), |
| - base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread, |
| - this)); |
| + base::Bind(&CreateTempFile), |
| + base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempEmfReady, |
|
Lei Zhang
2014/09/16 03:36:54
Can you move the OnTempEmfReady() impl to be right
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
|
| + this, |
| + page_number)); |
| +} |
| + |
| +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_Succeeded, OnSucceeded) |
| - IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed, |
| - OnFailed) |
| + ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount) |
| + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, |
| + OnPageDone) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| return handled; |
| } |
| -void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - if (!utility_process_host_) { |
| - RunCallbackOnUIThread(std::vector<printing::PageRange>(), 0.0); |
| - return; |
| - } |
| - |
| - 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(); |
| -} |
| - |
| -void PdfToEmfUtilityProcessHostClient::OnSucceeded( |
| - const std::vector<printing::PageRange>& page_ranges, |
| - double scale_factor) { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - RunCallback(page_ranges, scale_factor); |
| +bool PdfToEmfUtilityProcessHostClient::Send(IPC::Message* msg) { |
| + if (utility_process_host_) |
| + return utility_process_host_->Send(msg); |
| + delete msg; |
| + return false; |
| } |
| -void PdfToEmfUtilityProcessHostClient::OnFailed() { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - RunCallback(std::vector<printing::PageRange>(), 0.0); |
| -} |
| +void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (!utility_process_host_) |
| + return OnFailed(); |
| -void PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread() { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| - if (!files_->IsValid()) { |
| - RunCallbackOnUIThread(std::vector<printing::PageRange>(), 0.0); |
| - return; |
| - } |
| - BrowserThread::PostTask( |
| - BrowserThread::IO, |
| + 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::StartProcessOnIOThread, |
| - this)); |
| + base::Bind(&CreateTempPdfFile, data), |
| + base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this)); |
|
Lei Zhang
2014/09/16 03:36:54
and move OnTempPdfReady to right after this.
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
|
| } |
| -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); |
| +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::RunCallback( |
| - const std::vector<printing::PageRange>& page_ranges, |
| - double scale_factor) { |
| +void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success, |
| + double scale_factor) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (get_page_callbacks_.empty()) |
| + return OnFailed(); |
| + scoped_ptr<LazyEmf> emf; |
| + if (success) |
| + emf.reset(new LazyEmf(get_page_callbacks_.begin()->second.second.Pass())); |
|
Lei Zhang
2014/09/16 03:36:54
nit: save the iterator from get_page_callbacks_.be
Lei Zhang
2014/09/16 03:36:54
If you are using get_page_callbacks_.begin() here,
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Actually this is a bug.
Works fine with current cl
|
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| - base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread, |
| - this, |
| - page_ranges, |
| - scale_factor)); |
| + base::Bind(&PdfToEmfConverterImpl::RunCallback, |
| + converter_, |
| + base::Bind(get_page_callbacks_.begin()->second.first, |
| + get_page_callbacks_.begin()->first, |
| + scale_factor, |
| + base::Passed(&emf)))); |
| + get_page_callbacks_.erase(get_page_callbacks_.begin()); |
| } |
| -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()); |
| - } |
| - } |
| - files_ = NULL; |
| - if (!callback_.is_null()) { |
| - callback_.Run(scale_factor, &pages); |
| - callback_.Reset(); |
| - } |
| +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(); |
| } |
| -class PdfToEmfConverterImpl : public PdfToEmfConverter { |
| - public: |
| - PdfToEmfConverterImpl(); |
| - |
| - virtual ~PdfToEmfConverterImpl(); |
| - |
| - virtual void Start(base::RefCountedMemory* data, |
| - const printing::PdfRenderSettings& conversion_settings, |
| - const ResultCallback& callback) OVERRIDE; |
| - |
| - private: |
| - scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_; |
| - base::CancelableCallback<ResultCallback::RunType> callback_; |
| +void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(TempFilePtr pdf) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (!utility_process_host_) |
| + return OnFailed(); |
| + base::ProcessHandle process = utility_process_host_->GetData().handle; |
| + Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles( |
| + IPC::GetFileHandleForProcess(pdf->GetPlatformFile(), process, false), |
| + settings_)); |
| +} |
| - DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl); |
| -}; |
| +void PdfToEmfUtilityProcessHostClient::OnTempEmfReady(int page_number, |
| + TempFilePtr emf) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (!utility_process_host_ || get_page_callbacks_.count(page_number) != 1) |
|
Lei Zhang
2014/09/16 03:36:54
nit: ContainsKey(get_page_callbacks_, page_number)
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
|
| + return OnFailed(); |
| + base::ProcessHandle process = utility_process_host_->GetData().handle; |
| + IPC::PlatformFileForTransit transit = |
| + IPC::GetFileHandleForProcess(emf->GetPlatformFile(), process, false); |
| + get_page_callbacks_[page_number].second = emf.Pass(); |
| + Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage(page_number, |
| + transit)); |
| +} |
| -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()); |