#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"
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();
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");
}
}
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_;
};
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:
double scale_factor);
void OnFilesReadyOnUIThread();
- scoped_ptr<FileHandlers> files_;
+ scoped_refptr<FileHandlers> files_;
printing::PdfRenderSettings settings_;
PdfToEmfConverter::ResultCallback callback_;
base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
: settings_(settings) {}
PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
- // Delete temp directory.
- BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, files_.release());
}
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));
}
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();
}
}