OLD | NEW |
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(); |
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 virtual ~TempEmf() {} |
| 105 |
| 106 virtual bool SafePlayback(HDC hdc) const OVERRIDE { |
| 107 bool result = Emf::SafePlayback(hdc); |
| 108 TempEmf* this_mutable = const_cast<TempEmf*>(this); |
| 109 // TODO(vitalybuka): Fix destruction of metafiles. For some reasons |
| 110 // instances of Emf are not deleted. crbug.com/411683 |
| 111 // |files_| must be released as soon as possible to guarantee deletion. |
| 112 // It's know that this Emf file is going to be played just once to |
| 113 // a printer. So just release files here. |
| 114 this_mutable->Close(); |
| 115 this_mutable->files_ = NULL; |
| 116 return result; |
| 117 } |
| 118 |
| 119 private: |
| 120 scoped_refptr<FileHandlers> files_; |
| 121 DISALLOW_COPY_AND_ASSIGN(TempEmf); |
| 122 }; |
| 123 |
84 // Converts PDF into EMF. | 124 // Converts PDF into EMF. |
85 // Class uses 3 threads: UI, IO and FILE. | 125 // Class uses 3 threads: UI, IO and FILE. |
86 // Internal workflow is following: | 126 // Internal workflow is following: |
87 // 1. Create instance on the UI thread. (files_, settings_,) | 127 // 1. Create instance on the UI thread. (files_, settings_,) |
88 // 2. Create file on the FILE thread. | 128 // 2. Create file on the FILE thread. |
89 // 3. Start utility process and start conversion on the IO thread. | 129 // 3. Start utility process and start conversion on the IO thread. |
90 // 4. Run result callback on the UI thread. | 130 // 4. Run result callback on the UI thread. |
91 // 5. Instance is destroyed from any thread that has the last reference. | 131 // 5. Instance is destroyed from any thread that has the last reference. |
92 // 6. FileHandlers destroyed on the FILE thread. | 132 // 6. FileHandlers destroyed on the FILE thread. |
93 // This step posts |FileHandlers| to be destroyed on the FILE thread. | 133 // This step posts |FileHandlers| to be destroyed on the FILE thread. |
(...skipping 24 matching lines...) Expand all Loading... |
118 void RunCallback(const std::vector<printing::PageRange>& page_ranges, | 158 void RunCallback(const std::vector<printing::PageRange>& page_ranges, |
119 double scale_factor); | 159 double scale_factor); |
120 | 160 |
121 void StartProcessOnIOThread(); | 161 void StartProcessOnIOThread(); |
122 | 162 |
123 void RunCallbackOnUIThread( | 163 void RunCallbackOnUIThread( |
124 const std::vector<printing::PageRange>& page_ranges, | 164 const std::vector<printing::PageRange>& page_ranges, |
125 double scale_factor); | 165 double scale_factor); |
126 void OnFilesReadyOnUIThread(); | 166 void OnFilesReadyOnUIThread(); |
127 | 167 |
128 scoped_ptr<FileHandlers, BrowserThread::DeleteOnFileThread> files_; | 168 scoped_refptr<FileHandlers> files_; |
129 printing::PdfRenderSettings settings_; | 169 printing::PdfRenderSettings settings_; |
130 PdfToEmfConverter::ResultCallback callback_; | 170 PdfToEmfConverter::ResultCallback callback_; |
131 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; | 171 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; |
132 | 172 |
133 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); | 173 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); |
134 }; | 174 }; |
135 | 175 |
136 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( | 176 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( |
137 const printing::PdfRenderSettings& settings) | 177 const printing::PdfRenderSettings& settings) |
138 : settings_(settings) {} | 178 : settings_(settings) {} |
139 | 179 |
140 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { | 180 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { |
141 } | 181 } |
142 | 182 |
143 void PdfToEmfUtilityProcessHostClient::Convert( | 183 void PdfToEmfUtilityProcessHostClient::Convert( |
144 base::RefCountedMemory* data, | 184 base::RefCountedMemory* data, |
145 const PdfToEmfConverter::ResultCallback& callback) { | 185 const PdfToEmfConverter::ResultCallback& callback) { |
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
147 callback_ = callback; | 187 callback_ = callback; |
148 CHECK(!files_); | 188 CHECK(!files_.get()); |
149 files_.reset(new FileHandlers()); | 189 files_ = new FileHandlers(); |
150 BrowserThread::PostTaskAndReply( | 190 BrowserThread::PostTaskAndReply( |
151 BrowserThread::FILE, | 191 BrowserThread::FILE, |
152 FROM_HERE, | 192 FROM_HERE, |
153 base::Bind(&FileHandlers::Init, | 193 base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)), |
154 base::Unretained(files_.get()), | |
155 make_scoped_refptr(data)), | |
156 base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread, | 194 base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread, |
157 this)); | 195 this)); |
158 } | 196 } |
159 | 197 |
160 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { | 198 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { |
161 OnFailed(); | 199 OnFailed(); |
162 } | 200 } |
163 | 201 |
164 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( | 202 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( |
165 const IPC::Message& message) { | 203 const IPC::Message& message) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread, | 277 base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread, |
240 this, | 278 this, |
241 page_ranges, | 279 page_ranges, |
242 scale_factor)); | 280 scale_factor)); |
243 } | 281 } |
244 | 282 |
245 void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread( | 283 void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread( |
246 const std::vector<printing::PageRange>& page_ranges, | 284 const std::vector<printing::PageRange>& page_ranges, |
247 double scale_factor) { | 285 double scale_factor) { |
248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
249 std::vector<base::FilePath> page_filenames; | 287 ScopedVector<Metafile> pages; |
250 std::vector<printing::PageRange>::const_iterator iter; | 288 std::vector<printing::PageRange>::const_iterator iter; |
251 for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) { | 289 for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) { |
252 for (int page_number = iter->from; page_number <= iter->to; ++page_number) { | 290 for (int page_number = iter->from; page_number <= iter->to; ++page_number) { |
253 page_filenames.push_back(files_->GetEmfPath().InsertBeforeExtensionASCII( | 291 scoped_ptr<TempEmf> metafile(new TempEmf(files_)); |
254 base::StringPrintf(".%d", page_number))); | 292 if (!metafile->InitFromFile(files_->GetEmfPagePath(page_number))) { |
| 293 NOTREACHED() << "Invalid metafile"; |
| 294 metafile.reset(); |
| 295 } |
| 296 pages.push_back(metafile.release()); |
255 } | 297 } |
256 } | 298 } |
| 299 files_ = NULL; |
257 if (!callback_.is_null()) { | 300 if (!callback_.is_null()) { |
258 BrowserThread::PostTask( | 301 callback_.Run(scale_factor, &pages); |
259 BrowserThread::UI, | |
260 FROM_HERE, | |
261 base::Bind(callback_, scale_factor, page_filenames)); | |
262 callback_.Reset(); | 302 callback_.Reset(); |
263 } | 303 } |
264 } | 304 } |
265 | 305 |
266 class PdfToEmfConverterImpl : public PdfToEmfConverter { | 306 class PdfToEmfConverterImpl : public PdfToEmfConverter { |
267 public: | 307 public: |
268 PdfToEmfConverterImpl(); | 308 PdfToEmfConverterImpl(); |
269 | 309 |
270 virtual ~PdfToEmfConverterImpl(); | 310 virtual ~PdfToEmfConverterImpl(); |
271 | 311 |
(...skipping 26 matching lines...) Expand all Loading... |
298 } | 338 } |
299 | 339 |
300 } // namespace | 340 } // namespace |
301 | 341 |
302 // static | 342 // static |
303 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { | 343 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { |
304 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); | 344 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); |
305 } | 345 } |
306 | 346 |
307 } // namespace printing | 347 } // namespace printing |
OLD | NEW |