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..8aa80572a311ac6c600a15d2e0684b1cf071c400 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,52 @@ 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(); |
scottmg
2014/09/08 19:06:11
I'm not sure why it was re-opened readonly before,
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:57
I see no reason why it's bad, because target proce
|
} |
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() {}; |
scottmg
2014/09/08 19:06:10
no ;
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:58
Done.
|
+ |
+ 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 |
scottmg
2014/09/08 19:06:11
that seems pretty worrying, do you have any insigh
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:57
Yes PrintedDocument. I have no more details yet, b
|
+ // |files_| must be released as soon as possible to guaranty deletion. |
scottmg
2014/09/08 19:06:10
nit; guaranty -> guarantee
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:58
Done.
|
+ // It's know that that this Emf file is going to be played just once to |
scottmg
2014/09/08 19:06:10
nit; "know that that" -> "known that"
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:58
Done.
|
+ // 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 +166,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 +186,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 +285,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(); |
} |
} |