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" | |
8 #include "base/cancelable_callback.h" | |
9 #include "base/files/file.h" | 7 #include "base/files/file.h" |
10 #include "base/files/file_util.h" | 8 #include "base/files/file_util.h" |
11 #include "base/files/scoped_temp_dir.h" | |
12 #include "base/logging.h" | 9 #include "base/logging.h" |
13 #include "chrome/common/chrome_utility_messages.h" | 10 #include "chrome/common/chrome_utility_messages.h" |
14 #include "chrome/common/chrome_utility_printing_messages.h" | 11 #include "chrome/common/chrome_utility_printing_messages.h" |
15 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
16 #include "content/public/browser/child_process_data.h" | 13 #include "content/public/browser/child_process_data.h" |
17 #include "content/public/browser/utility_process_host.h" | 14 #include "content/public/browser/utility_process_host.h" |
18 #include "content/public/browser/utility_process_host_client.h" | 15 #include "content/public/browser/utility_process_host_client.h" |
19 #include "printing/emf_win.h" | 16 #include "printing/emf_win.h" |
20 #include "printing/page_range.h" | |
21 #include "printing/pdf_render_settings.h" | 17 #include "printing/pdf_render_settings.h" |
22 | 18 |
23 namespace printing { | 19 namespace printing { |
24 | 20 |
25 namespace { | 21 namespace { |
26 | 22 |
27 using content::BrowserThread; | 23 using content::BrowserThread; |
28 | 24 |
29 class FileHandlers | 25 class PdfToEmfConverterImpl; |
30 : public base::RefCountedThreadSafe<FileHandlers, | 26 |
31 BrowserThread::DeleteOnFileThread> { | 27 typedef scoped_ptr<base::File, BrowserThread::DeleteOnFileThread> TempFilePtr; |
Lei Zhang
2014/09/16 03:36:54
Maybe rename TempFilePtr to ScopedTempFile?
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
| |
28 | |
29 // Wrapper for Emf to keep only file handle in memory, and load actual data only | |
30 // on playback. |InitFromFile| can play metafile directly from disk, but it | |
Lei Zhang
2014/09/16 03:36:54
nit: |InitFromFile| -> Emf::InitFromFile()
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
| |
31 // can't open file handles. We need file handles to reliably delete temporary | |
32 // files, and to efficiently interact with sandbox process. | |
Lei Zhang
2014/09/16 03:36:54
nit: sandbox -> utility?
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
| |
33 class LazyEmf : public MetafilePlayer { | |
32 public: | 34 public: |
33 FileHandlers() {} | 35 explicit LazyEmf(TempFilePtr file) : file_(file.Pass()) {} |
34 | 36 virtual ~LazyEmf() { Close(); } |
35 void Init(base::RefCountedMemory* data); | 37 |
36 bool IsValid(); | 38 virtual bool SafePlayback(HDC hdc) const OVERRIDE; |
37 | 39 virtual bool SaveTo(base::File* file) const OVERRIDE; |
38 base::FilePath GetEmfPath() const { | |
39 return temp_dir_.path().AppendASCII("output.emf"); | |
40 } | |
41 | |
42 base::FilePath GetEmfPagePath(int page_number) const { | |
43 return GetEmfPath().InsertBeforeExtensionASCII( | |
44 base::StringPrintf(".%d", page_number)); | |
45 } | |
46 | |
47 base::FilePath GetPdfPath() const { | |
48 return temp_dir_.path().AppendASCII("input.pdf"); | |
49 } | |
50 | |
51 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) { | |
52 DCHECK(pdf_file_.IsValid()); | |
53 IPC::PlatformFileForTransit transit = | |
54 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process); | |
55 return transit; | |
56 } | |
57 | |
58 const base::FilePath& GetBasePath() const { | |
59 return temp_dir_.path(); | |
60 } | |
61 | 40 |
62 private: | 41 private: |
63 friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>; | 42 void Close() const; |
64 friend class base::DeleteHelper<FileHandlers>; | 43 bool LoadEmf(Emf* emf) const; |
65 | 44 |
66 ~FileHandlers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); } | 45 mutable TempFilePtr file_; // Mutable because of consts in base class. |
67 | 46 DISALLOW_COPY_AND_ASSIGN(LazyEmf); |
68 base::ScopedTempDir temp_dir_; | |
69 base::File pdf_file_; | |
70 }; | |
71 | |
72 void FileHandlers::Init(base::RefCountedMemory* data) { | |
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
74 | |
75 if (!temp_dir_.CreateUniqueTempDir()) { | |
76 return; | |
77 } | |
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); | |
83 if (static_cast<int>(data->size()) != | |
84 pdf_file_.WriteAtCurrentPos(data->front_as<char>(), data->size())) { | |
85 pdf_file_.Close(); | |
86 return; | |
87 } | |
88 pdf_file_.Seek(base::File::FROM_BEGIN, 0); | |
89 pdf_file_.Flush(); | |
90 } | |
91 | |
92 bool FileHandlers::IsValid() { | |
93 return pdf_file_.IsValid(); | |
94 } | |
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 }; | 47 }; |
123 | 48 |
124 // Converts PDF into EMF. | 49 // Converts PDF into EMF. |
125 // Class uses 3 threads: UI, IO and FILE. | 50 // Class uses 3 threads: UI, IO and FILE. |
126 // Internal workflow is following: | 51 // Internal workflow is following: |
127 // 1. Create instance on the UI thread. (files_, settings_,) | 52 // 1. Create instance on the UI thread. (files_, settings_,) |
128 // 2. Create file on the FILE thread. | 53 // 2. Create pdf file on the FILE thread. |
129 // 3. Start utility process and start conversion on the IO thread. | 54 // 3. Start utility process and start conversion on the IO thread. |
130 // 4. Run result callback on the UI thread. | 55 // 4. Utility process returns page count. |
131 // 5. Instance is destroyed from any thread that has the last reference. | 56 // 5. For each page: |
132 // 6. FileHandlers destroyed on the FILE thread. | 57 // 1. Clients requiquest page with file handle to temp file. |
Lei Zhang
2014/09/16 03:36:54
typo
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
| |
133 // This step posts |FileHandlers| to be destroyed on the FILE thread. | 58 // 2. Utility converts the page, save it to the file and reply. |
59 | |
134 // All these steps work sequentially, so no data should be accessed | 60 // All these steps work sequentially, so no data should be accessed |
135 // simultaneously by several threads. | 61 // simultaneously by several threads. |
136 class PdfToEmfUtilityProcessHostClient | 62 class PdfToEmfUtilityProcessHostClient |
137 : public content::UtilityProcessHostClient { | 63 : public content::UtilityProcessHostClient { |
138 public: | 64 public: |
139 explicit PdfToEmfUtilityProcessHostClient( | 65 PdfToEmfUtilityProcessHostClient( |
140 const printing::PdfRenderSettings& settings); | 66 base::WeakPtr<PdfToEmfConverterImpl> converter, |
141 | 67 const PdfRenderSettings& settings); |
142 void Convert(base::RefCountedMemory* data, | 68 |
143 const PdfToEmfConverter::ResultCallback& callback); | 69 void Start(const scoped_refptr<base::RefCountedMemory>& data, |
70 const PdfToEmfConverter::StartCallback& start_callback); | |
71 | |
72 void GetPage(int page_number, | |
73 const PdfToEmfConverter::GetPageCallback& get_page_callback); | |
74 | |
75 void Stop(); | |
144 | 76 |
145 // UtilityProcessHostClient implementation. | 77 // UtilityProcessHostClient implementation. |
146 virtual void OnProcessCrashed(int exit_code) OVERRIDE; | 78 virtual void OnProcessCrashed(int exit_code) OVERRIDE; |
79 virtual void OnProcessLaunchFailed() OVERRIDE; | |
147 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; | 80 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; |
148 | 81 |
149 private: | 82 private: |
150 virtual ~PdfToEmfUtilityProcessHostClient(); | 83 virtual ~PdfToEmfUtilityProcessHostClient(); |
151 | 84 |
85 bool Send(IPC::Message* msg); | |
86 | |
152 // Message handlers. | 87 // Message handlers. |
153 void OnProcessStarted(); | 88 void OnProcessStarted(); |
154 void OnSucceeded(const std::vector<printing::PageRange>& page_ranges, | 89 void OnPageCount(int page_count); |
155 double scale_factor); | 90 void OnPageDone(bool success, double scale_factor); |
91 | |
156 void OnFailed(); | 92 void OnFailed(); |
157 | 93 void OnTempPdfReady(TempFilePtr pdf); |
158 void RunCallback(const std::vector<printing::PageRange>& page_ranges, | 94 void OnTempEmfReady(int page_number, TempFilePtr emf); |
159 double scale_factor); | 95 |
160 | 96 // Used to suppress callbacks after PdfToEmfConverterImpl is deleted. |
161 void StartProcessOnIOThread(); | 97 base::WeakPtr<PdfToEmfConverterImpl> converter_; |
162 | 98 PdfRenderSettings settings_; |
163 void RunCallbackOnUIThread( | 99 scoped_refptr<base::RefCountedMemory> data_; |
164 const std::vector<printing::PageRange>& page_ranges, | 100 |
165 double scale_factor); | 101 // Document loaded callback. |
166 void OnFilesReadyOnUIThread(); | 102 PdfToEmfConverter::StartCallback start_callback_; |
167 | 103 |
168 scoped_refptr<FileHandlers> files_; | 104 // Process host for IPC. |
169 printing::PdfRenderSettings settings_; | |
170 PdfToEmfConverter::ResultCallback callback_; | |
171 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; | 105 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; |
172 | 106 |
107 std::map<int, std::pair<PdfToEmfConverter::GetPageCallback, TempFilePtr> > | |
Lei Zhang
2014/09/16 03:36:54
document what the key is.
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
| |
108 get_page_callbacks_; | |
109 | |
173 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); | 110 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); |
174 }; | 111 }; |
175 | 112 |
113 class PdfToEmfConverterImpl : public PdfToEmfConverter { | |
114 public: | |
115 PdfToEmfConverterImpl(); | |
116 | |
117 virtual ~PdfToEmfConverterImpl(); | |
118 | |
119 virtual void Start(const scoped_refptr<base::RefCountedMemory>& data, | |
120 const PdfRenderSettings& conversion_settings, | |
121 const StartCallback& start_callback) OVERRIDE; | |
122 | |
123 virtual void GetPage(int page_number, | |
124 const GetPageCallback& get_page_callback) OVERRIDE; | |
125 | |
126 // Helps to cancel callbacks if this object is destroyed. | |
127 void RunCallback(const base::Closure& callback); | |
128 | |
129 private: | |
130 scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_; | |
131 base::WeakPtrFactory<PdfToEmfConverterImpl> weak_ptr_factory_; | |
132 | |
133 DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl); | |
134 }; | |
135 | |
136 TempFilePtr CreateTempFile() { | |
137 TempFilePtr file; | |
138 base::FilePath path; | |
139 if (!base::CreateTemporaryFile(&path)) | |
140 return file.Pass(); | |
141 file.reset(new base::File(path, | |
142 base::File::FLAG_CREATE_ALWAYS | | |
143 base::File::FLAG_WRITE | base::File::FLAG_READ | | |
144 base::File::FLAG_DELETE_ON_CLOSE | | |
145 base::File::FLAG_TEMPORARY)); | |
146 if (!file->IsValid()) | |
147 file.reset(); | |
148 return file.Pass(); | |
149 } | |
150 | |
151 TempFilePtr CreateTempPdfFile( | |
152 const scoped_refptr<base::RefCountedMemory>& data) { | |
153 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
154 | |
155 TempFilePtr pdf_file = CreateTempFile(); | |
156 if (!pdf_file || | |
157 static_cast<int>(data->size()) != | |
158 pdf_file->WriteAtCurrentPos(data->front_as<char>(), data->size())) { | |
159 pdf_file.reset(); | |
160 } | |
161 pdf_file->Seek(base::File::FROM_BEGIN, 0); | |
162 return pdf_file.Pass(); | |
163 } | |
164 | |
165 bool LazyEmf::SafePlayback(HDC hdc) const { | |
166 Emf emf; | |
167 bool result = LoadEmf(&emf) && emf.SafePlayback(hdc); | |
168 // TODO(vitalybuka): Fix destruction of metafiles. For some reasons | |
169 // instances of Emf are not deleted. crbug.com/411683 | |
170 // It's known that the Emf going to be played just once to a printer. So just | |
171 // release file here. | |
172 Close(); | |
173 return result; | |
174 } | |
175 | |
176 bool LazyEmf::SaveTo(base::File* file) const { | |
177 Emf emf; | |
178 return LoadEmf(&emf) && emf.SaveTo(file); | |
179 } | |
180 | |
181 void LazyEmf::Close() const { | |
182 file_.reset(); | |
183 } | |
184 | |
185 bool LazyEmf::LoadEmf(Emf* emf) const { | |
186 file_->Seek(base::File::FROM_BEGIN, 0); | |
187 int64 size = file_->GetLength(); | |
188 if (size <= 0) | |
189 return false; | |
190 std::vector<char> data(size); | |
191 if (file_->ReadAtCurrentPos(data.data(), data.size()) != size) | |
192 return false; | |
193 return emf->InitFromData(data.data(), data.size()); | |
194 } | |
195 | |
176 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( | 196 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( |
177 const printing::PdfRenderSettings& settings) | 197 base::WeakPtr<PdfToEmfConverterImpl> converter, |
178 : settings_(settings) {} | 198 const PdfRenderSettings& settings) |
199 : converter_(converter), settings_(settings) { | |
200 } | |
179 | 201 |
180 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { | 202 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { |
181 } | 203 } |
182 | 204 |
183 void PdfToEmfUtilityProcessHostClient::Convert( | 205 void PdfToEmfUtilityProcessHostClient::Start( |
184 base::RefCountedMemory* data, | 206 const scoped_refptr<base::RefCountedMemory>& data, |
185 const PdfToEmfConverter::ResultCallback& callback) { | 207 const PdfToEmfConverter::StartCallback& start_callback) { |
186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 208 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
187 callback_ = callback; | 209 BrowserThread::PostTask(BrowserThread::IO, |
188 CHECK(!files_.get()); | 210 FROM_HERE, |
189 files_ = new FileHandlers(); | 211 base::Bind(&PdfToEmfUtilityProcessHostClient::Start, |
190 BrowserThread::PostTaskAndReply( | 212 this, |
213 data, | |
214 start_callback)); | |
215 return; | |
216 } | |
217 data_ = data; | |
218 start_callback_ = start_callback; | |
219 | |
220 // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load | |
221 // gdiplus.dll, change how rendering happens, and not be able to correctly | |
222 // generate when sent to a metafile DC. | |
223 utility_process_host_ = | |
224 content::UtilityProcessHost::Create( | |
225 this, base::MessageLoop::current()->message_loop_proxy()) | |
226 ->AsWeakPtr(); | |
227 if (!utility_process_host_) | |
228 return OnFailed(); | |
229 Send(new ChromeUtilityMsg_StartupPing); | |
230 } | |
231 | |
232 void PdfToEmfUtilityProcessHostClient::GetPage( | |
233 int page_number, | |
234 const PdfToEmfConverter::GetPageCallback& get_page_callback) { | |
235 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
236 BrowserThread::PostTask( | |
237 BrowserThread::IO, | |
238 FROM_HERE, | |
239 base::Bind(&PdfToEmfUtilityProcessHostClient::GetPage, | |
240 this, | |
241 page_number, | |
242 get_page_callback)); | |
243 return; | |
244 } | |
245 | |
246 bool new_request = | |
247 get_page_callbacks_.insert(std::make_pair( | |
248 page_number, | |
249 std::make_pair(get_page_callback, | |
250 TempFilePtr()))).second; | |
251 DCHECK(new_request) << "Multiple requests for the same page"; | |
252 if (!new_request || !utility_process_host_) | |
253 return OnFailed(); | |
254 | |
255 BrowserThread::PostTaskAndReplyWithResult( | |
191 BrowserThread::FILE, | 256 BrowserThread::FILE, |
192 FROM_HERE, | 257 FROM_HERE, |
193 base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)), | 258 base::Bind(&CreateTempFile), |
194 base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread, | 259 base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempEmfReady, |
Lei Zhang
2014/09/16 03:36:54
Can you move the OnTempEmfReady() impl to be right
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
| |
195 this)); | 260 this, |
261 page_number)); | |
262 } | |
263 | |
264 void PdfToEmfUtilityProcessHostClient::Stop() { | |
265 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
266 BrowserThread::PostTask( | |
267 BrowserThread::IO, | |
268 FROM_HERE, | |
269 base::Bind(&PdfToEmfUtilityProcessHostClient::Stop, this)); | |
270 return; | |
271 } | |
272 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop()); | |
196 } | 273 } |
197 | 274 |
198 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { | 275 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { |
199 OnFailed(); | 276 OnFailed(); |
200 } | 277 } |
201 | 278 |
279 void PdfToEmfUtilityProcessHostClient::OnProcessLaunchFailed() { | |
280 OnFailed(); | |
281 } | |
282 | |
202 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( | 283 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( |
203 const IPC::Message& message) { | 284 const IPC::Message& message) { |
204 bool handled = true; | 285 bool handled = true; |
205 IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message) | 286 IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message) |
206 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) | 287 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) |
207 IPC_MESSAGE_HANDLER( | 288 IPC_MESSAGE_HANDLER( |
208 ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_Succeeded, OnSucceeded) | 289 ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount) |
209 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed, | 290 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, |
210 OnFailed) | 291 OnPageDone) |
211 IPC_MESSAGE_UNHANDLED(handled = false) | 292 IPC_MESSAGE_UNHANDLED(handled = false) |
212 IPC_END_MESSAGE_MAP() | 293 IPC_END_MESSAGE_MAP() |
213 return handled; | 294 return handled; |
214 } | 295 } |
215 | 296 |
297 bool PdfToEmfUtilityProcessHostClient::Send(IPC::Message* msg) { | |
298 if (utility_process_host_) | |
299 return utility_process_host_->Send(msg); | |
300 delete msg; | |
301 return false; | |
302 } | |
303 | |
216 void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { | 304 void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { |
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 305 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
218 if (!utility_process_host_) { | 306 if (!utility_process_host_) |
219 RunCallbackOnUIThread(std::vector<printing::PageRange>(), 0.0); | 307 return OnFailed(); |
220 return; | |
221 } | |
222 | 308 |
223 base::ProcessHandle process = utility_process_host_->GetData().handle; | 309 base::ProcessHandle process = utility_process_host_->GetData().handle; |
224 utility_process_host_->Send( | 310 scoped_refptr<base::RefCountedMemory> data = data_; |
225 new ChromeUtilityMsg_RenderPDFPagesToMetafiles( | 311 data_ = NULL; |
226 files_->GetPdfForProcess(process), | 312 BrowserThread::PostTaskAndReplyWithResult( |
227 files_->GetEmfPath(), | 313 BrowserThread::FILE, |
228 settings_, | |
229 std::vector<printing::PageRange>())); | |
230 utility_process_host_.reset(); | |
231 } | |
232 | |
233 void PdfToEmfUtilityProcessHostClient::OnSucceeded( | |
234 const std::vector<printing::PageRange>& page_ranges, | |
235 double scale_factor) { | |
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
237 RunCallback(page_ranges, scale_factor); | |
238 } | |
239 | |
240 void PdfToEmfUtilityProcessHostClient::OnFailed() { | |
241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
242 RunCallback(std::vector<printing::PageRange>(), 0.0); | |
243 } | |
244 | |
245 void PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread() { | |
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
247 if (!files_->IsValid()) { | |
248 RunCallbackOnUIThread(std::vector<printing::PageRange>(), 0.0); | |
249 return; | |
250 } | |
251 BrowserThread::PostTask( | |
252 BrowserThread::IO, | |
253 FROM_HERE, | 314 FROM_HERE, |
254 base::Bind(&PdfToEmfUtilityProcessHostClient::StartProcessOnIOThread, | 315 base::Bind(&CreateTempPdfFile, data), |
255 this)); | 316 base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this)); |
Lei Zhang
2014/09/16 03:36:54
and move OnTempPdfReady to right after this.
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
| |
256 } | 317 } |
257 | 318 |
258 void PdfToEmfUtilityProcessHostClient::StartProcessOnIOThread() { | 319 void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) { |
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 320 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
260 utility_process_host_ = | 321 if (start_callback_.is_null()) |
261 content::UtilityProcessHost::Create( | 322 return OnFailed(); |
262 this, | 323 BrowserThread::PostTask(BrowserThread::UI, |
263 base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr(); | 324 FROM_HERE, |
264 // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load | 325 base::Bind(&PdfToEmfConverterImpl::RunCallback, |
265 // gdiplus.dll, change how rendering happens, and not be able to correctly | 326 converter_, |
266 // generate when sent to a metafile DC. | 327 base::Bind(start_callback_, page_count))); |
267 utility_process_host_->SetExposedDir(files_->GetBasePath()); | 328 start_callback_.Reset(); |
268 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing); | 329 } |
269 } | 330 |
270 | 331 void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success, |
271 void PdfToEmfUtilityProcessHostClient::RunCallback( | 332 double scale_factor) { |
272 const std::vector<printing::PageRange>& page_ranges, | 333 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
273 double scale_factor) { | 334 if (get_page_callbacks_.empty()) |
335 return OnFailed(); | |
336 scoped_ptr<LazyEmf> emf; | |
337 if (success) | |
338 emf.reset(new LazyEmf(get_page_callbacks_.begin()->second.second.Pass())); | |
Lei Zhang
2014/09/16 03:36:54
nit: save the iterator from get_page_callbacks_.be
Lei Zhang
2014/09/16 03:36:54
If you are using get_page_callbacks_.begin() here,
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Actually this is a bug.
Works fine with current cl
| |
274 BrowserThread::PostTask( | 339 BrowserThread::PostTask( |
275 BrowserThread::UI, | 340 BrowserThread::UI, |
276 FROM_HERE, | 341 FROM_HERE, |
277 base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread, | 342 base::Bind(&PdfToEmfConverterImpl::RunCallback, |
278 this, | 343 converter_, |
279 page_ranges, | 344 base::Bind(get_page_callbacks_.begin()->second.first, |
280 scale_factor)); | 345 get_page_callbacks_.begin()->first, |
281 } | 346 scale_factor, |
282 | 347 base::Passed(&emf)))); |
283 void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread( | 348 get_page_callbacks_.erase(get_page_callbacks_.begin()); |
284 const std::vector<printing::PageRange>& page_ranges, | 349 } |
285 double scale_factor) { | 350 |
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 351 void PdfToEmfUtilityProcessHostClient::OnFailed() { |
287 ScopedVector<MetafilePlayer> pages; | 352 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
288 std::vector<printing::PageRange>::const_iterator iter; | 353 if (!start_callback_.is_null()) |
289 for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) { | 354 OnPageCount(0); |
290 for (int page_number = iter->from; page_number <= iter->to; ++page_number) { | 355 while (!get_page_callbacks_.empty()) |
291 scoped_ptr<TempEmf> metafile(new TempEmf(files_)); | 356 OnPageDone(false, 0.0); |
292 if (!metafile->InitFromFile(files_->GetEmfPagePath(page_number))) { | 357 utility_process_host_.reset(); |
293 NOTREACHED() << "Invalid metafile"; | 358 } |
294 metafile.reset(); | 359 |
295 } | 360 void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(TempFilePtr pdf) { |
296 pages.push_back(metafile.release()); | 361 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
297 } | 362 if (!utility_process_host_) |
298 } | 363 return OnFailed(); |
299 files_ = NULL; | 364 base::ProcessHandle process = utility_process_host_->GetData().handle; |
300 if (!callback_.is_null()) { | 365 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles( |
301 callback_.Run(scale_factor, &pages); | 366 IPC::GetFileHandleForProcess(pdf->GetPlatformFile(), process, false), |
302 callback_.Reset(); | 367 settings_)); |
303 } | 368 } |
304 } | 369 |
305 | 370 void PdfToEmfUtilityProcessHostClient::OnTempEmfReady(int page_number, |
306 class PdfToEmfConverterImpl : public PdfToEmfConverter { | 371 TempFilePtr emf) { |
307 public: | 372 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
308 PdfToEmfConverterImpl(); | 373 if (!utility_process_host_ || get_page_callbacks_.count(page_number) != 1) |
Lei Zhang
2014/09/16 03:36:54
nit: ContainsKey(get_page_callbacks_, page_number)
Vitaly Buka (NO REVIEWS)
2014/09/16 07:50:35
Done.
| |
309 | 374 return OnFailed(); |
310 virtual ~PdfToEmfConverterImpl(); | 375 base::ProcessHandle process = utility_process_host_->GetData().handle; |
311 | 376 IPC::PlatformFileForTransit transit = |
312 virtual void Start(base::RefCountedMemory* data, | 377 IPC::GetFileHandleForProcess(emf->GetPlatformFile(), process, false); |
313 const printing::PdfRenderSettings& conversion_settings, | 378 get_page_callbacks_[page_number].second = emf.Pass(); |
314 const ResultCallback& callback) OVERRIDE; | 379 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage(page_number, |
315 | 380 transit)); |
316 private: | 381 } |
317 scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_; | 382 |
318 base::CancelableCallback<ResultCallback::RunType> callback_; | 383 PdfToEmfConverterImpl::PdfToEmfConverterImpl() : weak_ptr_factory_(this) { |
319 | |
320 DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl); | |
321 }; | |
322 | |
323 PdfToEmfConverterImpl::PdfToEmfConverterImpl() { | |
324 } | 384 } |
325 | 385 |
326 PdfToEmfConverterImpl::~PdfToEmfConverterImpl() { | 386 PdfToEmfConverterImpl::~PdfToEmfConverterImpl() { |
387 if (utility_client_) | |
388 utility_client_->Stop(); | |
327 } | 389 } |
328 | 390 |
329 void PdfToEmfConverterImpl::Start( | 391 void PdfToEmfConverterImpl::Start( |
330 base::RefCountedMemory* data, | 392 const scoped_refptr<base::RefCountedMemory>& data, |
331 const printing::PdfRenderSettings& conversion_settings, | 393 const PdfRenderSettings& conversion_settings, |
332 const ResultCallback& callback) { | 394 const StartCallback& start_callback) { |
333 // Rebind cancelable callback to avoid calling callback if | 395 DCHECK(!utility_client_); |
334 // PdfToEmfConverterImpl is destroyed. | 396 utility_client_ = new PdfToEmfUtilityProcessHostClient( |
335 callback_.Reset(callback); | 397 weak_ptr_factory_.GetWeakPtr(), conversion_settings); |
336 utility_client_ = new PdfToEmfUtilityProcessHostClient(conversion_settings); | 398 utility_client_->Start(data, start_callback); |
337 utility_client_->Convert(data, callback_.callback()); | 399 } |
400 | |
401 void PdfToEmfConverterImpl::GetPage(int page_number, | |
402 const GetPageCallback& get_page_callback) { | |
403 utility_client_->GetPage(page_number, get_page_callback); | |
404 } | |
405 | |
406 void PdfToEmfConverterImpl::RunCallback(const base::Closure& callback) { | |
407 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
408 callback.Run(); | |
338 } | 409 } |
339 | 410 |
340 } // namespace | 411 } // namespace |
341 | 412 |
413 PdfToEmfConverter::~PdfToEmfConverter() { | |
414 } | |
415 | |
342 // static | 416 // static |
343 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { | 417 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { |
344 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); | 418 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); |
345 } | 419 } |
346 | 420 |
347 } // namespace printing | 421 } // namespace printing |
OLD | NEW |