pwg_raster_converter.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/local_discovery/pwg_raster_converter.h" 6 7#include "base/bind_helpers.h" 8#include "base/cancelable_callback.h" 9#include "base/files/file.h" 10#include "base/files/file_util.h" 11#include "base/files/scoped_temp_dir.h" 12#include "base/logging.h" 13#include "chrome/common/chrome_utility_messages.h" 14#include "chrome/common/chrome_utility_printing_messages.h" 15#include "content/public/browser/browser_thread.h" 16#include "content/public/browser/child_process_data.h" 17#include "content/public/browser/utility_process_host.h" 18#include "content/public/browser/utility_process_host_client.h" 19#include "printing/pdf_render_settings.h" 20#include "printing/pwg_raster_settings.h" 21 22namespace local_discovery { 23 24namespace { 25 26using content::BrowserThread; 27 28class FileHandlers { 29 public: 30 FileHandlers() {} 31 32 ~FileHandlers() { 33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 34 } 35 36 void Init(base::RefCountedMemory* data); 37 bool IsValid(); 38 39 base::FilePath GetPwgPath() const { 40 return temp_dir_.path().AppendASCII("output.pwg"); 41 } 42 43 base::FilePath GetPdfPath() const { 44 return temp_dir_.path().AppendASCII("input.pdf"); 45 } 46 47 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) { 48 DCHECK(pdf_file_.IsValid()); 49 IPC::PlatformFileForTransit transit = 50 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process); 51 return transit; 52 } 53 54 IPC::PlatformFileForTransit GetPwgForProcess(base::ProcessHandle process) { 55 DCHECK(pwg_file_.IsValid()); 56 IPC::PlatformFileForTransit transit = 57 IPC::TakeFileHandleForProcess(pwg_file_.Pass(), process); 58 return transit; 59 } 60 61 private: 62 base::ScopedTempDir temp_dir_; 63 base::File pdf_file_; 64 base::File pwg_file_; 65}; 66 67void FileHandlers::Init(base::RefCountedMemory* data) { 68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 69 70 if (!temp_dir_.CreateUniqueTempDir()) { 71 return; 72 } 73 74 if (static_cast<int>(data->size()) != 75 base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) { 76 return; 77 } 78 79 // Reopen in read only mode. 80 pdf_file_.Initialize(GetPdfPath(), 81 base::File::FLAG_OPEN | base::File::FLAG_READ); 82 pwg_file_.Initialize(GetPwgPath(), 83 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); 84} 85 86bool FileHandlers::IsValid() { 87 return pdf_file_.IsValid() && pwg_file_.IsValid(); 88} 89 90// Converts PDF into PWG raster. 91// Class uses 3 threads: UI, IO and FILE. 92// Internal workflow is following: 93// 1. Create instance on the UI thread. (files_, settings_,) 94// 2. Create file on the FILE thread. 95// 3. Start utility process and start conversion on the IO thread. 96// 4. Run result callback on the UI thread. 97// 5. Instance is destroyed from any thread that has the last reference. 98// 6. FileHandlers destroyed on the FILE thread. 99// This step posts |FileHandlers| to be destroyed on the FILE thread. 100// All these steps work sequentially, so no data should be accessed 101// simultaneously by several threads. 102class PwgUtilityProcessHostClient : public content::UtilityProcessHostClient { 103 public: 104 explicit PwgUtilityProcessHostClient( 105 const printing::PdfRenderSettings& settings, 106 const printing::PwgRasterSettings& bitmap_settings); 107 108 void Convert(base::RefCountedMemory* data, 109 const PWGRasterConverter::ResultCallback& callback); 110 111 // UtilityProcessHostClient implementation. 112 virtual void OnProcessCrashed(int exit_code) OVERRIDE; 113 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 114 115 private: 116 virtual ~PwgUtilityProcessHostClient(); 117 118 // Message handlers. 119 void OnProcessStarted(); 120 void OnSucceeded(); 121 void OnFailed(); 122 123 void RunCallback(bool success); 124 125 void StartProcessOnIOThread(); 126 127 void RunCallbackOnUIThread(bool success); 128 void OnFilesReadyOnUIThread(); 129 130 scoped_ptr<FileHandlers, BrowserThread::DeleteOnFileThread> files_; 131 printing::PdfRenderSettings settings_; 132 printing::PwgRasterSettings bitmap_settings_; 133 PWGRasterConverter::ResultCallback callback_; 134 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; 135 136 DISALLOW_COPY_AND_ASSIGN(PwgUtilityProcessHostClient); 137}; 138 139PwgUtilityProcessHostClient::PwgUtilityProcessHostClient( 140 const printing::PdfRenderSettings& settings, 141 const printing::PwgRasterSettings& bitmap_settings) 142 : settings_(settings), bitmap_settings_(bitmap_settings) {} 143 144PwgUtilityProcessHostClient::~PwgUtilityProcessHostClient() { 145} 146 147void PwgUtilityProcessHostClient::Convert( 148 base::RefCountedMemory* data, 149 const PWGRasterConverter::ResultCallback& callback) { 150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 151 callback_ = callback; 152 CHECK(!files_); 153 files_.reset(new FileHandlers()); 154 BrowserThread::PostTaskAndReply( 155 BrowserThread::FILE, FROM_HERE, 156 base::Bind(&FileHandlers::Init, base::Unretained(files_.get()), 157 make_scoped_refptr(data)), 158 base::Bind(&PwgUtilityProcessHostClient::OnFilesReadyOnUIThread, this)); 159} 160 161void PwgUtilityProcessHostClient::OnProcessCrashed(int exit_code) { 162 OnFailed(); 163} 164 165bool PwgUtilityProcessHostClient::OnMessageReceived( 166 const IPC::Message& message) { 167 bool handled = true; 168 IPC_BEGIN_MESSAGE_MAP(PwgUtilityProcessHostClient, message) 169 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) 170 IPC_MESSAGE_HANDLER( 171 ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded, OnSucceeded) 172 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed, 173 OnFailed) 174 IPC_MESSAGE_UNHANDLED(handled = false) 175 IPC_END_MESSAGE_MAP() 176 return handled; 177} 178 179void PwgUtilityProcessHostClient::OnProcessStarted() { 180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 181 if (!utility_process_host_) { 182 RunCallbackOnUIThread(false); 183 return; 184 } 185 186 base::ProcessHandle process = utility_process_host_->GetData().handle; 187 utility_process_host_->Send(new ChromeUtilityMsg_RenderPDFPagesToPWGRaster( 188 files_->GetPdfForProcess(process), 189 settings_, 190 bitmap_settings_, 191 files_->GetPwgForProcess(process))); 192 utility_process_host_.reset(); 193} 194 195void PwgUtilityProcessHostClient::OnSucceeded() { 196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 197 RunCallback(true); 198} 199 200void PwgUtilityProcessHostClient::OnFailed() { 201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 202 RunCallback(false); 203} 204 205void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() { 206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 207 if (!files_->IsValid()) { 208 RunCallbackOnUIThread(false); 209 return; 210 } 211 BrowserThread::PostTask( 212 BrowserThread::IO, FROM_HERE, 213 base::Bind(&PwgUtilityProcessHostClient::StartProcessOnIOThread, this)); 214} 215 216void PwgUtilityProcessHostClient::StartProcessOnIOThread() { 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 218 utility_process_host_ = 219 content::UtilityProcessHost::Create( 220 this, 221 base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr(); 222 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing); 223} 224 225void PwgUtilityProcessHostClient::RunCallback(bool success) { 226 BrowserThread::PostTask( 227 BrowserThread::UI, FROM_HERE, 228 base::Bind(&PwgUtilityProcessHostClient::RunCallbackOnUIThread, this, 229 success)); 230} 231 232void PwgUtilityProcessHostClient::RunCallbackOnUIThread(bool success) { 233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 234 if (!callback_.is_null()) { 235 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 236 base::Bind(callback_, success, 237 files_->GetPwgPath())); 238 callback_.Reset(); 239 } 240} 241 242class PWGRasterConverterImpl : public PWGRasterConverter { 243 public: 244 PWGRasterConverterImpl(); 245 246 virtual ~PWGRasterConverterImpl(); 247 248 virtual void Start(base::RefCountedMemory* data, 249 const printing::PdfRenderSettings& conversion_settings, 250 const printing::PwgRasterSettings& bitmap_settings, 251 const ResultCallback& callback) OVERRIDE; 252 253 private: 254 scoped_refptr<PwgUtilityProcessHostClient> utility_client_; 255 base::CancelableCallback<ResultCallback::RunType> callback_; 256 257 DISALLOW_COPY_AND_ASSIGN(PWGRasterConverterImpl); 258}; 259 260PWGRasterConverterImpl::PWGRasterConverterImpl() { 261} 262 263PWGRasterConverterImpl::~PWGRasterConverterImpl() { 264} 265 266void PWGRasterConverterImpl::Start( 267 base::RefCountedMemory* data, 268 const printing::PdfRenderSettings& conversion_settings, 269 const printing::PwgRasterSettings& bitmap_settings, 270 const ResultCallback& callback) { 271 // Rebind cancelable callback to avoid calling callback if 272 // PWGRasterConverterImpl is destroyed. 273 callback_.Reset(callback); 274 utility_client_ = 275 new PwgUtilityProcessHostClient(conversion_settings, bitmap_settings); 276 utility_client_->Convert(data, callback_.callback()); 277} 278 279} // namespace 280 281// static 282scoped_ptr<PWGRasterConverter> PWGRasterConverter::CreateDefault() { 283 return scoped_ptr<PWGRasterConverter>(new PWGRasterConverterImpl()); 284} 285 286} // namespace local_discovery 287