Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: chrome/browser/printing/pdf_to_emf_converter.cc

Issue 547203002: Delete temporarily dir for PDF to EMF conversion after all EMF files closed. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Mon Sep 8 11:44:50 PDT 2014 Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/printing/pdf_to_emf_converter.h" 5 #include "chrome/browser/printing/pdf_to_emf_converter.h"
6 6
7 #include "base/bind_helpers.h" 7 #include "base/bind_helpers.h"
8 #include "base/cancelable_callback.h" 8 #include "base/cancelable_callback.h"
9 #include "base/files/file.h" 9 #include "base/files/file.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h" 11 #include "base/files/scoped_temp_dir.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "chrome/common/chrome_utility_messages.h" 13 #include "chrome/common/chrome_utility_messages.h"
14 #include "chrome/common/chrome_utility_printing_messages.h" 14 #include "chrome/common/chrome_utility_printing_messages.h"
15 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/child_process_data.h" 16 #include "content/public/browser/child_process_data.h"
17 #include "content/public/browser/utility_process_host.h" 17 #include "content/public/browser/utility_process_host.h"
18 #include "content/public/browser/utility_process_host_client.h" 18 #include "content/public/browser/utility_process_host_client.h"
19 #include "printing/emf_win.h"
19 #include "printing/page_range.h" 20 #include "printing/page_range.h"
20 #include "printing/pdf_render_settings.h" 21 #include "printing/pdf_render_settings.h"
21 22
22 namespace printing { 23 namespace printing {
23 24
24 namespace { 25 namespace {
25 26
26 using content::BrowserThread; 27 using content::BrowserThread;
27 28
28 class FileHandlers { 29 class FileHandlers
30 : public base::RefCountedThreadSafe<FileHandlers,
31 BrowserThread::DeleteOnFileThread> {
29 public: 32 public:
30 FileHandlers() {} 33 FileHandlers() {}
31 34
32 ~FileHandlers() {
33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
34 }
35
36 void Init(base::RefCountedMemory* data); 35 void Init(base::RefCountedMemory* data);
37 bool IsValid(); 36 bool IsValid();
38 37
39 base::FilePath GetEmfPath() const { 38 base::FilePath GetEmfPath() const {
40 return temp_dir_.path().AppendASCII("output.emf"); 39 return temp_dir_.path().AppendASCII("output.emf");
41 } 40 }
42 41
42 base::FilePath GetEmfPagePath(int page_number) const {
43 return GetEmfPath().InsertBeforeExtensionASCII(
44 base::StringPrintf(".%d", page_number));
45 }
46
43 base::FilePath GetPdfPath() const { 47 base::FilePath GetPdfPath() const {
44 return temp_dir_.path().AppendASCII("input.pdf"); 48 return temp_dir_.path().AppendASCII("input.pdf");
45 } 49 }
46 50
47 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) { 51 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) {
48 DCHECK(pdf_file_.IsValid()); 52 DCHECK(pdf_file_.IsValid());
49 IPC::PlatformFileForTransit transit = 53 IPC::PlatformFileForTransit transit =
50 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process); 54 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process);
51 return transit; 55 return transit;
52 } 56 }
53 57
54 const base::FilePath& GetBasePath() const { 58 const base::FilePath& GetBasePath() const {
55 return temp_dir_.path(); 59 return temp_dir_.path();
56 } 60 }
57 61
58 private: 62 private:
63 friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
64 friend class base::DeleteHelper<FileHandlers>;
65
66 ~FileHandlers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); }
67
59 base::ScopedTempDir temp_dir_; 68 base::ScopedTempDir temp_dir_;
60 base::File pdf_file_; 69 base::File pdf_file_;
61 }; 70 };
62 71
63 void FileHandlers::Init(base::RefCountedMemory* data) { 72 void FileHandlers::Init(base::RefCountedMemory* data) {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
65 74
66 if (!temp_dir_.CreateUniqueTempDir()) { 75 if (!temp_dir_.CreateUniqueTempDir()) {
67 return; 76 return;
68 } 77 }
69 78
79 pdf_file_.Initialize(GetPdfPath(),
80 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
81 base::File::FLAG_READ |
82 base::File::FLAG_DELETE_ON_CLOSE);
70 if (static_cast<int>(data->size()) != 83 if (static_cast<int>(data->size()) !=
71 base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) { 84 pdf_file_.WriteAtCurrentPos(data->front_as<char>(), data->size())) {
85 pdf_file_.Close();
72 return; 86 return;
73 } 87 }
74 88 pdf_file_.Seek(base::File::FROM_BEGIN, 0);
75 // Reopen in read only mode. 89 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
76 pdf_file_.Initialize(GetPdfPath(),
77 base::File::FLAG_OPEN | base::File::FLAG_READ);
78 } 90 }
79 91
80 bool FileHandlers::IsValid() { 92 bool FileHandlers::IsValid() {
81 return pdf_file_.IsValid(); 93 return pdf_file_.IsValid();
82 } 94 }
83 95
96 // Modification of Emf to keep references to |FileHandlers|.
97 // |FileHandlers| must be deleted after the last metafile is closed because
98 // Emf holds files locked.
99 // Ideally we want to use FLAG_DELETE_ON_CLOSE, but it requires large changes.
100 // It's going to be done for crbug.com/408184
101 class TempEmf : public Emf {
102 public:
103 explicit TempEmf(const scoped_refptr<FileHandlers>& files) : files_(files) {}
104
105 virtual ~TempEmf() {};
scottmg 2014/09/08 19:06:10 no ;
Vitaly Buka (NO REVIEWS) 2014/09/08 19:19:58 Done.
106
107 virtual bool SafePlayback(HDC hdc) const OVERRIDE {
108 bool result = Emf::SafePlayback(hdc);
109 TempEmf* this_mutable = const_cast<TempEmf*>(this);
110 // TODO(vitalybuka): Fix destruction of metafiles. For some reasons
111 // 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
112 // |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.
113 // 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.
114 // a printer. So just release files here.
115 this_mutable->Close();
116 this_mutable->files_ = NULL;
117 return result;
118 }
119
120 private:
121 scoped_refptr<FileHandlers> files_;
122 DISALLOW_COPY_AND_ASSIGN(TempEmf);
123 };
124
84 // Converts PDF into EMF. 125 // Converts PDF into EMF.
85 // Class uses 3 threads: UI, IO and FILE. 126 // Class uses 3 threads: UI, IO and FILE.
86 // Internal workflow is following: 127 // Internal workflow is following:
87 // 1. Create instance on the UI thread. (files_, settings_,) 128 // 1. Create instance on the UI thread. (files_, settings_,)
88 // 2. Create file on the FILE thread. 129 // 2. Create file on the FILE thread.
89 // 3. Start utility process and start conversion on the IO thread. 130 // 3. Start utility process and start conversion on the IO thread.
90 // 4. Run result callback on the UI thread. 131 // 4. Run result callback on the UI thread.
91 // 5. Instance is destroyed from any thread that has the last reference. 132 // 5. Instance is destroyed from any thread that has the last reference.
92 // 6. FileHandlers destroyed on the FILE thread. 133 // 6. FileHandlers destroyed on the FILE thread.
93 // This step posts |FileHandlers| to be destroyed on the FILE thread. 134 // This step posts |FileHandlers| to be destroyed on the FILE thread.
(...skipping 24 matching lines...) Expand all
118 void RunCallback(const std::vector<printing::PageRange>& page_ranges, 159 void RunCallback(const std::vector<printing::PageRange>& page_ranges,
119 double scale_factor); 160 double scale_factor);
120 161
121 void StartProcessOnIOThread(); 162 void StartProcessOnIOThread();
122 163
123 void RunCallbackOnUIThread( 164 void RunCallbackOnUIThread(
124 const std::vector<printing::PageRange>& page_ranges, 165 const std::vector<printing::PageRange>& page_ranges,
125 double scale_factor); 166 double scale_factor);
126 void OnFilesReadyOnUIThread(); 167 void OnFilesReadyOnUIThread();
127 168
128 scoped_ptr<FileHandlers, BrowserThread::DeleteOnFileThread> files_; 169 scoped_refptr<FileHandlers> files_;
129 printing::PdfRenderSettings settings_; 170 printing::PdfRenderSettings settings_;
130 PdfToEmfConverter::ResultCallback callback_; 171 PdfToEmfConverter::ResultCallback callback_;
131 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; 172 base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
132 173
133 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); 174 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient);
134 }; 175 };
135 176
136 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( 177 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
137 const printing::PdfRenderSettings& settings) 178 const printing::PdfRenderSettings& settings)
138 : settings_(settings) {} 179 : settings_(settings) {}
139 180
140 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { 181 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
141 } 182 }
142 183
143 void PdfToEmfUtilityProcessHostClient::Convert( 184 void PdfToEmfUtilityProcessHostClient::Convert(
144 base::RefCountedMemory* data, 185 base::RefCountedMemory* data,
145 const PdfToEmfConverter::ResultCallback& callback) { 186 const PdfToEmfConverter::ResultCallback& callback) {
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
147 callback_ = callback; 188 callback_ = callback;
148 CHECK(!files_); 189 CHECK(!files_.get());
149 files_.reset(new FileHandlers()); 190 files_ = new FileHandlers();
150 BrowserThread::PostTaskAndReply( 191 BrowserThread::PostTaskAndReply(
151 BrowserThread::FILE, 192 BrowserThread::FILE,
152 FROM_HERE, 193 FROM_HERE,
153 base::Bind(&FileHandlers::Init, 194 base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)),
154 base::Unretained(files_.get()),
155 make_scoped_refptr(data)),
156 base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread, 195 base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread,
157 this)); 196 this));
158 } 197 }
159 198
160 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { 199 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) {
161 OnFailed(); 200 OnFailed();
162 } 201 }
163 202
164 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( 203 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived(
165 const IPC::Message& message) { 204 const IPC::Message& message) {
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread, 278 base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread,
240 this, 279 this,
241 page_ranges, 280 page_ranges,
242 scale_factor)); 281 scale_factor));
243 } 282 }
244 283
245 void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread( 284 void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread(
246 const std::vector<printing::PageRange>& page_ranges, 285 const std::vector<printing::PageRange>& page_ranges,
247 double scale_factor) { 286 double scale_factor) {
248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
249 std::vector<base::FilePath> page_filenames; 288 ScopedVector<Metafile> pages;
250 std::vector<printing::PageRange>::const_iterator iter; 289 std::vector<printing::PageRange>::const_iterator iter;
251 for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) { 290 for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) {
252 for (int page_number = iter->from; page_number <= iter->to; ++page_number) { 291 for (int page_number = iter->from; page_number <= iter->to; ++page_number) {
253 page_filenames.push_back(files_->GetEmfPath().InsertBeforeExtensionASCII( 292 scoped_ptr<TempEmf> metafile(new TempEmf(files_));
254 base::StringPrintf(".%d", page_number))); 293 if (!metafile->InitFromFile(files_->GetEmfPagePath(page_number))) {
294 NOTREACHED() << "Invalid metafile";
295 metafile.reset();
296 }
297 pages.push_back(metafile.release());
255 } 298 }
256 } 299 }
300 files_ = NULL;
257 if (!callback_.is_null()) { 301 if (!callback_.is_null()) {
258 BrowserThread::PostTask( 302 callback_.Run(scale_factor, &pages);
259 BrowserThread::UI,
260 FROM_HERE,
261 base::Bind(callback_, scale_factor, page_filenames));
262 callback_.Reset(); 303 callback_.Reset();
263 } 304 }
264 } 305 }
265 306
266 class PdfToEmfConverterImpl : public PdfToEmfConverter { 307 class PdfToEmfConverterImpl : public PdfToEmfConverter {
267 public: 308 public:
268 PdfToEmfConverterImpl(); 309 PdfToEmfConverterImpl();
269 310
270 virtual ~PdfToEmfConverterImpl(); 311 virtual ~PdfToEmfConverterImpl();
271 312
(...skipping 26 matching lines...) Expand all
298 } 339 }
299 340
300 } // namespace 341 } // namespace
301 342
302 // static 343 // static
303 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { 344 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() {
304 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); 345 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl());
305 } 346 }
306 347
307 } // namespace printing 348 } // namespace printing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698