Commit e12ae0b0 authored by Vitaly Buka's avatar Vitaly Buka

Delete temporarily dir for PDF to EMF conversion after EMF files closed.

printing::Emf keeps files locked so base::ScopedTempDir can't delete them and leaks files.

Failures or crashes still may leak files. I ignore them to have change simple enough for merging into beta.

BUG=411681
NOTRY=true
R=scottmg@chromium.org, thestig@chromium.org

Review URL: https://codereview.chromium.org/547203002

Cr-Commit-Position: refs/heads/master@{#293848}
parent 19378d2e
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "content/public/browser/child_process_data.h" #include "content/public/browser/child_process_data.h"
#include "content/public/browser/utility_process_host.h" #include "content/public/browser/utility_process_host.h"
#include "content/public/browser/utility_process_host_client.h" #include "content/public/browser/utility_process_host_client.h"
#include "printing/emf_win.h"
#include "printing/page_range.h" #include "printing/page_range.h"
#include "printing/pdf_render_settings.h" #include "printing/pdf_render_settings.h"
...@@ -25,14 +26,12 @@ namespace { ...@@ -25,14 +26,12 @@ namespace {
using content::BrowserThread; using content::BrowserThread;
class FileHandlers { class FileHandlers
: public base::RefCountedThreadSafe<FileHandlers,
BrowserThread::DeleteOnFileThread> {
public: public:
FileHandlers() {} FileHandlers() {}
~FileHandlers() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
}
void Init(base::RefCountedMemory* data); void Init(base::RefCountedMemory* data);
bool IsValid(); bool IsValid();
...@@ -40,6 +39,11 @@ class FileHandlers { ...@@ -40,6 +39,11 @@ class FileHandlers {
return temp_dir_.path().AppendASCII("output.emf"); 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 { base::FilePath GetPdfPath() const {
return temp_dir_.path().AppendASCII("input.pdf"); return temp_dir_.path().AppendASCII("input.pdf");
} }
...@@ -56,6 +60,11 @@ class FileHandlers { ...@@ -56,6 +60,11 @@ class FileHandlers {
} }
private: private:
friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
friend class base::DeleteHelper<FileHandlers>;
~FileHandlers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); }
base::ScopedTempDir temp_dir_; base::ScopedTempDir temp_dir_;
base::File pdf_file_; base::File pdf_file_;
}; };
...@@ -67,20 +76,51 @@ void FileHandlers::Init(base::RefCountedMemory* data) { ...@@ -67,20 +76,51 @@ void FileHandlers::Init(base::RefCountedMemory* data) {
return; 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()) != 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; return;
} }
pdf_file_.Seek(base::File::FROM_BEGIN, 0);
// Reopen in read only mode. pdf_file_.Flush();
pdf_file_.Initialize(GetPdfPath(),
base::File::FLAG_OPEN | base::File::FLAG_READ);
} }
bool FileHandlers::IsValid() { bool FileHandlers::IsValid() {
return pdf_file_.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. // Converts PDF into EMF.
// Class uses 3 threads: UI, IO and FILE. // Class uses 3 threads: UI, IO and FILE.
// Internal workflow is following: // Internal workflow is following:
...@@ -125,7 +165,7 @@ class PdfToEmfUtilityProcessHostClient ...@@ -125,7 +165,7 @@ class PdfToEmfUtilityProcessHostClient
double scale_factor); double scale_factor);
void OnFilesReadyOnUIThread(); void OnFilesReadyOnUIThread();
scoped_ptr<FileHandlers, BrowserThread::DeleteOnFileThread> files_; scoped_refptr<FileHandlers> files_;
printing::PdfRenderSettings settings_; printing::PdfRenderSettings settings_;
PdfToEmfConverter::ResultCallback callback_; PdfToEmfConverter::ResultCallback callback_;
base::WeakPtr<content::UtilityProcessHost> utility_process_host_; base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
...@@ -145,14 +185,12 @@ void PdfToEmfUtilityProcessHostClient::Convert( ...@@ -145,14 +185,12 @@ void PdfToEmfUtilityProcessHostClient::Convert(
const PdfToEmfConverter::ResultCallback& callback) { const PdfToEmfConverter::ResultCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
callback_ = callback; callback_ = callback;
CHECK(!files_); CHECK(!files_.get());
files_.reset(new FileHandlers()); files_ = new FileHandlers();
BrowserThread::PostTaskAndReply( BrowserThread::PostTaskAndReply(
BrowserThread::FILE, BrowserThread::FILE,
FROM_HERE, FROM_HERE,
base::Bind(&FileHandlers::Init, base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)),
base::Unretained(files_.get()),
make_scoped_refptr(data)),
base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread, base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread,
this)); this));
} }
...@@ -246,19 +284,21 @@ void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread( ...@@ -246,19 +284,21 @@ void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread(
const std::vector<printing::PageRange>& page_ranges, const std::vector<printing::PageRange>& page_ranges,
double scale_factor) { double scale_factor) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
std::vector<base::FilePath> page_filenames; ScopedVector<Metafile> pages;
std::vector<printing::PageRange>::const_iterator iter; std::vector<printing::PageRange>::const_iterator iter;
for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) { for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) {
for (int page_number = iter->from; page_number <= iter->to; ++page_number) { for (int page_number = iter->from; page_number <= iter->to; ++page_number) {
page_filenames.push_back(files_->GetEmfPath().InsertBeforeExtensionASCII( scoped_ptr<TempEmf> metafile(new TempEmf(files_));
base::StringPrintf(".%d", page_number))); if (!metafile->InitFromFile(files_->GetEmfPagePath(page_number))) {
NOTREACHED() << "Invalid metafile";
metafile.reset();
}
pages.push_back(metafile.release());
} }
} }
files_ = NULL;
if (!callback_.is_null()) { if (!callback_.is_null()) {
BrowserThread::PostTask( callback_.Run(scale_factor, &pages);
BrowserThread::UI,
FROM_HERE,
base::Bind(callback_, scale_factor, page_filenames));
callback_.Reset(); callback_.Reset();
} }
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/ref_counted_memory.h" #include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_vector.h"
namespace base { namespace base {
class FilePath; class FilePath;
...@@ -18,11 +19,14 @@ class PdfRenderSettings; ...@@ -18,11 +19,14 @@ class PdfRenderSettings;
namespace printing { namespace printing {
class Metafile;
class PdfToEmfConverter { class PdfToEmfConverter {
public: public:
// Callback for when the PDF is converted to an EMF. // Callback for when the PDF is converted to an EMF.
typedef base::Callback<void(double /*scale_factor*/, // Takes ownership of metafiles.
const std::vector<base::FilePath>& /*emf_files*/)> typedef base::Callback<
void(double /*scale_factor*/, ScopedVector<Metafile>* /*emf_files*/)>
ResultCallback; ResultCallback;
virtual ~PdfToEmfConverter() {} virtual ~PdfToEmfConverter() {}
......
...@@ -130,7 +130,7 @@ void PrintViewManagerBase::OnDidGetDocumentCookie(int cookie) { ...@@ -130,7 +130,7 @@ void PrintViewManagerBase::OnDidGetDocumentCookie(int cookie) {
void PrintViewManagerBase::OnPdfToEmfConverted( void PrintViewManagerBase::OnPdfToEmfConverted(
const PrintHostMsg_DidPrintPage_Params& params, const PrintHostMsg_DidPrintPage_Params& params,
double scale_factor, double scale_factor,
const std::vector<base::FilePath>& emf_files) { ScopedVector<Metafile>* emf_files) {
if (!print_job_.get()) if (!print_job_.get())
return; return;
...@@ -138,20 +138,23 @@ void PrintViewManagerBase::OnPdfToEmfConverted( ...@@ -138,20 +138,23 @@ void PrintViewManagerBase::OnPdfToEmfConverted(
if (!document) if (!document)
return; return;
for (size_t i = 0; i < emf_files.size(); ++i) { for (size_t i = 0; i < emf_files->size(); ++i) {
scoped_ptr<printing::Emf> metafile(new printing::Emf); if (!(*emf_files)[i]) {
if (!metafile->InitFromFile(emf_files[i])) {
NOTREACHED() << "Invalid metafile";
web_contents()->Stop(); web_contents()->Stop();
return; return;
} }
}
for (size_t i = 0; i < emf_files->size(); ++i) {
// Update the rendered document. It will send notifications to the listener. // Update the rendered document. It will send notifications to the listener.
document->SetPage(i, document->SetPage(i,
metafile.release(), (*emf_files)[i],
scale_factor, scale_factor,
params.page_size, params.page_size,
params.content_area); params.content_area);
} }
// document->SetPage took ownership of all EMFs.
emf_files->weak_clear();
ShouldQuitFromInnerMessageLoop(); ShouldQuitFromInnerMessageLoop();
} }
......
...@@ -23,6 +23,7 @@ class RenderViewHost; ...@@ -23,6 +23,7 @@ class RenderViewHost;
namespace printing { namespace printing {
class JobEventDetails; class JobEventDetails;
class Metafile;
class PdfToEmfConverter; class PdfToEmfConverter;
class PrintJob; class PrintJob;
class PrintJobWorkerOwner; class PrintJobWorkerOwner;
...@@ -137,7 +138,7 @@ class PrintViewManagerBase : public content::NotificationObserver, ...@@ -137,7 +138,7 @@ class PrintViewManagerBase : public content::NotificationObserver,
// Called on completion of converting the pdf to emf. // Called on completion of converting the pdf to emf.
void OnPdfToEmfConverted(const PrintHostMsg_DidPrintPage_Params& params, void OnPdfToEmfConverted(const PrintHostMsg_DidPrintPage_Params& params,
double scale_factor, double scale_factor,
const std::vector<base::FilePath>& emf_file); ScopedVector<Metafile>* emf_files);
#endif // OS_WIN #endif // OS_WIN
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
......
...@@ -169,9 +169,14 @@ Emf::Emf() : emf_(NULL), hdc_(NULL), page_count_(0) { ...@@ -169,9 +169,14 @@ Emf::Emf() : emf_(NULL), hdc_(NULL), page_count_(0) {
} }
Emf::~Emf() { Emf::~Emf() {
Close();
}
void Emf::Close() {
DCHECK(!hdc_); DCHECK(!hdc_);
if (emf_) if (emf_)
DeleteEnhMetaFile(emf_); DeleteEnhMetaFile(emf_);
emf_ = NULL;
} }
bool Emf::InitToFile(const base::FilePath& metafile_path) { bool Emf::InitToFile(const base::FilePath& metafile_path) {
......
...@@ -42,6 +42,9 @@ class PRINTING_EXPORT Emf : public Metafile { ...@@ -42,6 +42,9 @@ class PRINTING_EXPORT Emf : public Metafile {
Emf(); Emf();
virtual ~Emf(); virtual ~Emf();
// Closes metafile.
void Close();
// Generates a new metafile that will record every GDI command, and will // Generates a new metafile that will record every GDI command, and will
// be saved to |metafile_path|. // be saved to |metafile_path|.
virtual bool InitToFile(const base::FilePath& metafile_path); virtual bool InitToFile(const base::FilePath& metafile_path);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment