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(); |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |