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

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

Issue 566693002: Use file handles to interact with utility process. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Mon Sep 15 18:19:41 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"
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698