1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/printing/pdf_to_emf_converter.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <queue> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file_util.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/scoped_temp_dir.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_utility_messages.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_utility_printing_messages.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/child_process_data.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/utility_process_host.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/utility_process_host_client.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "printing/emf_win.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "printing/pdf_render_settings.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace printing { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PdfToEmfConverterImpl; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Allows to delete temporary directory after all temporary files created inside 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are closed. Windows cannot delete directory with opened files. Directory is 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// used to store PDF and metafiles. PDF should be gone by the time utility 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// process exits. Metafiles should be gone when all LazyEmf destroyed. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RefCountedTempDir 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public base::RefCountedThreadSafe<RefCountedTempDir, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::DeleteOnFileThread> { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RefCountedTempDir() { ignore_result(temp_dir_.CreateUniqueTempDir()); } 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool IsValid() const { return temp_dir_.IsValid(); } 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::FilePath& GetPath() const { return temp_dir_.path(); } 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private: 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>; 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) friend class base::DeleteHelper<RefCountedTempDir>; 454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ~RefCountedTempDir() {} 464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::ScopedTempDir temp_dir_; 484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir); 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)typedef scoped_ptr<base::File, BrowserThread::DeleteOnFileThread> 524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ScopedTempFile; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wrapper for Emf to keep only file handle in memory, and load actual data only 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on playback. Emf::InitFromFile() can play metafile directly from disk, but it 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// can't open file handles. We need file handles to reliably delete temporary 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// files, and to efficiently interact with utility process. 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class LazyEmf : public MetafilePlayer { 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public: 604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) LazyEmf(const scoped_refptr<RefCountedTempDir>& temp_dir, ScopedTempFile file) 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : temp_dir_(temp_dir), file_(file.Pass()) {} 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) virtual ~LazyEmf() { Close(); } 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) virtual bool SafePlayback(HDC hdc) const OVERRIDE; 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) virtual bool SaveTo(base::File* file) const OVERRIDE; 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private: 684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) void Close() const; 694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool LoadEmf(Emf* emf) const; 704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) mutable scoped_refptr<RefCountedTempDir> temp_dir_; 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) mutable ScopedTempFile file_; // Mutable because of consts in base class. 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(LazyEmf); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Converts PDF into EMF. 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Class uses 3 threads: UI, IO and FILE. 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Internal workflow is following: 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// 1. Create instance on the UI thread. (files_, settings_,) 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// 2. Create pdf file on the FILE thread. 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// 3. Start utility process and start conversion on the IO thread. 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// 4. Utility process returns page count. 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// 5. For each page: 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// 1. Clients requests page with file handle to a temp file. 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// 2. Utility converts the page, save it to the file and reply. 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// All these steps work sequentially, so no data should be accessed 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// simultaneously by several threads. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PdfToEmfUtilityProcessHostClient 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public content::UtilityProcessHostClient { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PdfToEmfUtilityProcessHostClient( 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtr<PdfToEmfConverterImpl> converter, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PdfRenderSettings& settings); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Start(const scoped_refptr<base::RefCountedMemory>& data, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PdfToEmfConverter::StartCallback& start_callback); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void GetPage(int page_number, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PdfToEmfConverter::GetPageCallback& get_page_callback); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Stop(); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // UtilityProcessHostClient implementation. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnProcessCrashed(int exit_code) OVERRIDE; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnProcessLaunchFailed() OVERRIDE; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class GetPageCallbackData { 1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) MOVE_ONLY_TYPE_FOR_CPP_03(GetPageCallbackData, RValue); 1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPageCallbackData(int page_number, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PdfToEmfConverter::GetPageCallback callback) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : page_number_(page_number), callback_(callback) {} 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Move constructor for STL. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPageCallbackData(RValue other) { this->operator=(other); } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Move assignment for STL. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPageCallbackData& operator=(RValue rhs) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_number_ = rhs.object->page_number_; 125 callback_ = rhs.object->callback_; 126 emf_ = rhs.object->emf_.Pass(); 127 return *this; 128 } 129 130 int page_number() const { return page_number_; } 131 const PdfToEmfConverter::GetPageCallback& callback() const { 132 return callback_; 133 } 134 ScopedTempFile emf() { return emf_.Pass(); } 135 void set_emf(ScopedTempFile emf) { emf_ = emf.Pass(); } 136 137 private: 138 int page_number_; 139 PdfToEmfConverter::GetPageCallback callback_; 140 ScopedTempFile emf_; 141 }; 142 143 virtual ~PdfToEmfUtilityProcessHostClient(); 144 145 bool Send(IPC::Message* msg); 146 147 // Message handlers. 148 void OnProcessStarted(); 149 void OnPageCount(int page_count); 150 void OnPageDone(bool success, double scale_factor); 151 152 void OnFailed(); 153 void OnTempPdfReady(ScopedTempFile pdf); 154 void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf); 155 156 scoped_refptr<RefCountedTempDir> temp_dir_; 157 158 // Used to suppress callbacks after PdfToEmfConverterImpl is deleted. 159 base::WeakPtr<PdfToEmfConverterImpl> converter_; 160 PdfRenderSettings settings_; 161 scoped_refptr<base::RefCountedMemory> data_; 162 163 // Document loaded callback. 164 PdfToEmfConverter::StartCallback start_callback_; 165 166 // Process host for IPC. 167 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; 168 169 // Queue of callbacks for GetPage() requests. Utility process should reply 170 // with PageDone in the same order as requests were received. 171 // Use containers that keeps element pointers valid after push() and pop(). 172 typedef std::queue<GetPageCallbackData> GetPageCallbacks; 173 GetPageCallbacks get_page_callbacks_; 174 175 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); 176}; 177 178class PdfToEmfConverterImpl : public PdfToEmfConverter { 179 public: 180 PdfToEmfConverterImpl(); 181 182 virtual ~PdfToEmfConverterImpl(); 183 184 virtual void Start(const scoped_refptr<base::RefCountedMemory>& data, 185 const PdfRenderSettings& conversion_settings, 186 const StartCallback& start_callback) OVERRIDE; 187 188 virtual void GetPage(int page_number, 189 const GetPageCallback& get_page_callback) OVERRIDE; 190 191 // Helps to cancel callbacks if this object is destroyed. 192 void RunCallback(const base::Closure& callback); 193 194 private: 195 scoped_refptr<PdfToEmfUtilityProcessHostClient> utility_client_; 196 base::WeakPtrFactory<PdfToEmfConverterImpl> weak_ptr_factory_; 197 198 DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl); 199}; 200 201ScopedTempFile CreateTempFile(scoped_refptr<RefCountedTempDir>* temp_dir) { 202 if (!temp_dir->get()) 203 *temp_dir = new RefCountedTempDir(); 204 ScopedTempFile file; 205 if (!(*temp_dir)->IsValid()) 206 return file.Pass(); 207 base::FilePath path; 208 if (!base::CreateTemporaryFileInDir((*temp_dir)->GetPath(), &path)) 209 return file.Pass(); 210 file.reset(new base::File(path, 211 base::File::FLAG_CREATE_ALWAYS | 212 base::File::FLAG_WRITE | 213 base::File::FLAG_READ | 214 base::File::FLAG_DELETE_ON_CLOSE | 215 base::File::FLAG_TEMPORARY)); 216 if (!file->IsValid()) 217 file.reset(); 218 return file.Pass(); 219} 220 221ScopedTempFile CreateTempPdfFile( 222 const scoped_refptr<base::RefCountedMemory>& data, 223 scoped_refptr<RefCountedTempDir>* temp_dir) { 224 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 225 226 ScopedTempFile pdf_file = CreateTempFile(temp_dir); 227 if (!pdf_file || 228 static_cast<int>(data->size()) != 229 pdf_file->WriteAtCurrentPos(data->front_as<char>(), data->size())) { 230 pdf_file.reset(); 231 } 232 pdf_file->Seek(base::File::FROM_BEGIN, 0); 233 return pdf_file.Pass(); 234} 235 236bool LazyEmf::SafePlayback(HDC hdc) const { 237 Emf emf; 238 bool result = LoadEmf(&emf) && emf.SafePlayback(hdc); 239 // TODO(vitalybuka): Fix destruction of metafiles. For some reasons 240 // instances of Emf are not deleted. crbug.com/411683 241 // It's known that the Emf going to be played just once to a printer. So just 242 // release file here. 243 Close(); 244 return result; 245} 246 247bool LazyEmf::SaveTo(base::File* file) const { 248 Emf emf; 249 return LoadEmf(&emf) && emf.SaveTo(file); 250} 251 252void LazyEmf::Close() const { 253 file_.reset(); 254 temp_dir_ = NULL; 255} 256 257bool LazyEmf::LoadEmf(Emf* emf) const { 258 file_->Seek(base::File::FROM_BEGIN, 0); 259 int64 size = file_->GetLength(); 260 if (size <= 0) 261 return false; 262 std::vector<char> data(size); 263 if (file_->ReadAtCurrentPos(data.data(), data.size()) != size) 264 return false; 265 return emf->InitFromData(data.data(), data.size()); 266} 267 268PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( 269 base::WeakPtr<PdfToEmfConverterImpl> converter, 270 const PdfRenderSettings& settings) 271 : converter_(converter), settings_(settings) { 272} 273 274PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { 275} 276 277void PdfToEmfUtilityProcessHostClient::Start( 278 const scoped_refptr<base::RefCountedMemory>& data, 279 const PdfToEmfConverter::StartCallback& start_callback) { 280 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 281 BrowserThread::PostTask(BrowserThread::IO, 282 FROM_HERE, 283 base::Bind(&PdfToEmfUtilityProcessHostClient::Start, 284 this, 285 data, 286 start_callback)); 287 return; 288 } 289 data_ = data; 290 291 // Store callback before any OnFailed() call to make it called on failure. 292 start_callback_ = start_callback; 293 294 // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load 295 // gdiplus.dll, change how rendering happens, and not be able to correctly 296 // generate when sent to a metafile DC. 297 utility_process_host_ = 298 content::UtilityProcessHost::Create( 299 this, base::MessageLoop::current()->message_loop_proxy()) 300 ->AsWeakPtr(); 301 if (!utility_process_host_) 302 return OnFailed(); 303 // Should reply with OnProcessStarted(). 304 Send(new ChromeUtilityMsg_StartupPing); 305} 306 307void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { 308 DCHECK_CURRENTLY_ON(BrowserThread::IO); 309 if (!utility_process_host_) 310 return OnFailed(); 311 312 scoped_refptr<base::RefCountedMemory> data = data_; 313 data_ = NULL; 314 BrowserThread::PostTaskAndReplyWithResult( 315 BrowserThread::FILE, 316 FROM_HERE, 317 base::Bind(&CreateTempPdfFile, data, &temp_dir_), 318 base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this)); 319} 320 321void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) { 322 DCHECK_CURRENTLY_ON(BrowserThread::IO); 323 if (!utility_process_host_) 324 return OnFailed(); 325 base::ProcessHandle process = utility_process_host_->GetData().handle; 326 // Should reply with OnPageCount(). 327 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles( 328 IPC::GetFileHandleForProcess(pdf->GetPlatformFile(), process, false), 329 settings_)); 330} 331 332void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) { 333 DCHECK_CURRENTLY_ON(BrowserThread::IO); 334 if (start_callback_.is_null()) 335 return OnFailed(); 336 BrowserThread::PostTask(BrowserThread::UI, 337 FROM_HERE, 338 base::Bind(&PdfToEmfConverterImpl::RunCallback, 339 converter_, 340 base::Bind(start_callback_, page_count))); 341 start_callback_.Reset(); 342} 343 344void PdfToEmfUtilityProcessHostClient::GetPage( 345 int page_number, 346 const PdfToEmfConverter::GetPageCallback& get_page_callback) { 347 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 348 BrowserThread::PostTask( 349 BrowserThread::IO, 350 FROM_HERE, 351 base::Bind(&PdfToEmfUtilityProcessHostClient::GetPage, 352 this, 353 page_number, 354 get_page_callback)); 355 return; 356 } 357 358 // Store callback before any OnFailed() call to make it called on failure. 359 get_page_callbacks_.push(GetPageCallbackData(page_number, get_page_callback)); 360 361 if (!utility_process_host_) 362 return OnFailed(); 363 364 BrowserThread::PostTaskAndReplyWithResult( 365 BrowserThread::FILE, 366 FROM_HERE, 367 base::Bind(&CreateTempFile, &temp_dir_), 368 base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempEmfReady, 369 this, 370 &get_page_callbacks_.back())); 371} 372 373void PdfToEmfUtilityProcessHostClient::OnTempEmfReady( 374 GetPageCallbackData* callback_data, 375 ScopedTempFile emf) { 376 DCHECK_CURRENTLY_ON(BrowserThread::IO); 377 if (!utility_process_host_) 378 return OnFailed(); 379 base::ProcessHandle process = utility_process_host_->GetData().handle; 380 IPC::PlatformFileForTransit transit = 381 IPC::GetFileHandleForProcess(emf->GetPlatformFile(), process, false); 382 callback_data->set_emf(emf.Pass()); 383 // Should reply with OnPageDone(). 384 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage( 385 callback_data->page_number(), transit)); 386} 387 388void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success, 389 double scale_factor) { 390 DCHECK_CURRENTLY_ON(BrowserThread::IO); 391 if (get_page_callbacks_.empty()) 392 return OnFailed(); 393 scoped_ptr<MetafilePlayer> emf; 394 GetPageCallbackData& data = get_page_callbacks_.front(); 395 if (success) 396 emf.reset(new LazyEmf(temp_dir_, data.emf().Pass())); 397 BrowserThread::PostTask(BrowserThread::UI, 398 FROM_HERE, 399 base::Bind(&PdfToEmfConverterImpl::RunCallback, 400 converter_, 401 base::Bind(data.callback(), 402 data.page_number(), 403 scale_factor, 404 base::Passed(&emf)))); 405 get_page_callbacks_.pop(); 406} 407 408void PdfToEmfUtilityProcessHostClient::Stop() { 409 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 410 BrowserThread::PostTask( 411 BrowserThread::IO, 412 FROM_HERE, 413 base::Bind(&PdfToEmfUtilityProcessHostClient::Stop, this)); 414 return; 415 } 416 Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop()); 417} 418 419void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { 420 OnFailed(); 421} 422 423void PdfToEmfUtilityProcessHostClient::OnProcessLaunchFailed() { 424 OnFailed(); 425} 426 427bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( 428 const IPC::Message& message) { 429 bool handled = true; 430 IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message) 431 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) 432 IPC_MESSAGE_HANDLER( 433 ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount) 434 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, 435 OnPageDone) 436 IPC_MESSAGE_UNHANDLED(handled = false) 437 IPC_END_MESSAGE_MAP() 438 return handled; 439} 440 441bool PdfToEmfUtilityProcessHostClient::Send(IPC::Message* msg) { 442 if (utility_process_host_) 443 return utility_process_host_->Send(msg); 444 delete msg; 445 return false; 446} 447 448void PdfToEmfUtilityProcessHostClient::OnFailed() { 449 DCHECK_CURRENTLY_ON(BrowserThread::IO); 450 if (!start_callback_.is_null()) 451 OnPageCount(0); 452 while (!get_page_callbacks_.empty()) 453 OnPageDone(false, 0.0); 454 utility_process_host_.reset(); 455} 456 457PdfToEmfConverterImpl::PdfToEmfConverterImpl() : weak_ptr_factory_(this) { 458} 459 460PdfToEmfConverterImpl::~PdfToEmfConverterImpl() { 461 if (utility_client_.get()) 462 utility_client_->Stop(); 463} 464 465void PdfToEmfConverterImpl::Start( 466 const scoped_refptr<base::RefCountedMemory>& data, 467 const PdfRenderSettings& conversion_settings, 468 const StartCallback& start_callback) { 469 DCHECK(!utility_client_.get()); 470 utility_client_ = new PdfToEmfUtilityProcessHostClient( 471 weak_ptr_factory_.GetWeakPtr(), conversion_settings); 472 utility_client_->Start(data, start_callback); 473} 474 475void PdfToEmfConverterImpl::GetPage(int page_number, 476 const GetPageCallback& get_page_callback) { 477 utility_client_->GetPage(page_number, get_page_callback); 478} 479 480void PdfToEmfConverterImpl::RunCallback(const base::Closure& callback) { 481 DCHECK_CURRENTLY_ON(BrowserThread::UI); 482 callback.Run(); 483} 484 485} // namespace 486 487PdfToEmfConverter::~PdfToEmfConverter() { 488} 489 490// static 491scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { 492 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); 493} 494 495} // namespace printing 496