| 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 df45a924a559b0bc06df798c05555322dc0ce159..ad99e3aadb8e81df48fb3a56e8a9b261d75b0a71 100644
|
| --- a/chrome/browser/printing/pdf_to_emf_converter.cc
|
| +++ b/chrome/browser/printing/pdf_to_emf_converter.cc
|
| @@ -16,6 +16,7 @@
|
| #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/page_range.h"
|
| #include "printing/pdf_render_settings.h"
|
|
|
| @@ -25,14 +26,12 @@ namespace {
|
|
|
| using content::BrowserThread;
|
|
|
| -class FileHandlers {
|
| +class FileHandlers
|
| + : public base::RefCountedThreadSafe<FileHandlers,
|
| + BrowserThread::DeleteOnFileThread> {
|
| public:
|
| FileHandlers() {}
|
|
|
| - ~FileHandlers() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - }
|
| -
|
| void Init(base::RefCountedMemory* data);
|
| bool IsValid();
|
|
|
| @@ -40,6 +39,11 @@ class FileHandlers {
|
| 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");
|
| }
|
| @@ -56,6 +60,11 @@ class FileHandlers {
|
| }
|
|
|
| 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_;
|
| };
|
| @@ -67,20 +76,51 @@ void FileHandlers::Init(base::RefCountedMemory* data) {
|
| return;
|
| }
|
|
|
| + 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()) !=
|
| - base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) {
|
| + pdf_file_.WriteAtCurrentPos(data->front_as<char>(), data->size())) {
|
| + pdf_file_.Close();
|
| return;
|
| }
|
| -
|
| - // Reopen in read only mode.
|
| - pdf_file_.Initialize(GetPdfPath(),
|
| - base::File::FLAG_OPEN | base::File::FLAG_READ);
|
| + 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);
|
| +};
|
| +
|
| // Converts PDF into EMF.
|
| // Class uses 3 threads: UI, IO and FILE.
|
| // Internal workflow is following:
|
| @@ -125,7 +165,7 @@ class PdfToEmfUtilityProcessHostClient
|
| double scale_factor);
|
| void OnFilesReadyOnUIThread();
|
|
|
| - scoped_ptr<FileHandlers, BrowserThread::DeleteOnFileThread> files_;
|
| + scoped_refptr<FileHandlers> files_;
|
| printing::PdfRenderSettings settings_;
|
| PdfToEmfConverter::ResultCallback callback_;
|
| base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
|
| @@ -145,14 +185,12 @@ void PdfToEmfUtilityProcessHostClient::Convert(
|
| const PdfToEmfConverter::ResultCallback& callback) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| callback_ = callback;
|
| - CHECK(!files_);
|
| - files_.reset(new FileHandlers());
|
| + CHECK(!files_.get());
|
| + files_ = new FileHandlers();
|
| BrowserThread::PostTaskAndReply(
|
| BrowserThread::FILE,
|
| FROM_HERE,
|
| - base::Bind(&FileHandlers::Init,
|
| - base::Unretained(files_.get()),
|
| - make_scoped_refptr(data)),
|
| + base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)),
|
| base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread,
|
| this));
|
| }
|
| @@ -246,19 +284,21 @@ void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread(
|
| const std::vector<printing::PageRange>& page_ranges,
|
| double scale_factor) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - std::vector<base::FilePath> page_filenames;
|
| + ScopedVector<Metafile> 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) {
|
| - page_filenames.push_back(files_->GetEmfPath().InsertBeforeExtensionASCII(
|
| - base::StringPrintf(".%d", 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()) {
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI,
|
| - FROM_HERE,
|
| - base::Bind(callback_, scale_factor, page_filenames));
|
| + callback_.Run(scale_factor, &pages);
|
| callback_.Reset();
|
| }
|
| }
|
|
|