pwg_raster_converter.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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/file_util.h" 10#include "base/files/file.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> 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 // Delete temp directory. 146 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, files_.release()); 147} 148 149void PwgUtilityProcessHostClient::Convert( 150 base::RefCountedMemory* data, 151 const PWGRasterConverter::ResultCallback& callback) { 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 153 callback_ = callback; 154 CHECK(!files_); 155 files_.reset(new FileHandlers()); 156 BrowserThread::PostTaskAndReply( 157 BrowserThread::FILE, FROM_HERE, 158 base::Bind(&FileHandlers::Init, base::Unretained(files_.get()), 159 make_scoped_refptr(data)), 160 base::Bind(&PwgUtilityProcessHostClient::OnFilesReadyOnUIThread, this)); 161} 162 163void PwgUtilityProcessHostClient::OnProcessCrashed(int exit_code) { 164 OnFailed(); 165} 166 167bool PwgUtilityProcessHostClient::OnMessageReceived( 168 const IPC::Message& message) { 169 bool handled = true; 170 IPC_BEGIN_MESSAGE_MAP(PwgUtilityProcessHostClient, message) 171 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) 172 IPC_MESSAGE_HANDLER( 173 ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded, OnSucceeded) 174 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed, 175 OnFailed) 176 IPC_MESSAGE_UNHANDLED(handled = false) 177 IPC_END_MESSAGE_MAP() 178 return handled; 179} 180 181void PwgUtilityProcessHostClient::OnProcessStarted() { 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 183 if (!utility_process_host_) { 184 RunCallbackOnUIThread(false); 185 return; 186 } 187 188 base::ProcessHandle process = utility_process_host_->GetData().handle; 189 utility_process_host_->Send(new ChromeUtilityMsg_RenderPDFPagesToPWGRaster( 190 files_->GetPdfForProcess(process), 191 settings_, 192 bitmap_settings_, 193 files_->GetPwgForProcess(process))); 194 utility_process_host_.reset(); 195} 196 197void PwgUtilityProcessHostClient::OnSucceeded() { 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 199 RunCallback(true); 200} 201 202void PwgUtilityProcessHostClient::OnFailed() { 203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 204 RunCallback(false); 205} 206 207void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() { 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 209 if (!files_->IsValid()) { 210 RunCallbackOnUIThread(false); 211 return; 212 } 213 BrowserThread::PostTask( 214 BrowserThread::IO, FROM_HERE, 215 base::Bind(&PwgUtilityProcessHostClient::StartProcessOnIOThread, this)); 216} 217 218void PwgUtilityProcessHostClient::StartProcessOnIOThread() { 219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 220 utility_process_host_ = 221 content::UtilityProcessHost::Create( 222 this, 223 base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr(); 224 utility_process_host_->Send(new ChromeUtilityMsg_StartupPing); 225} 226 227void PwgUtilityProcessHostClient::RunCallback(bool success) { 228 BrowserThread::PostTask( 229 BrowserThread::UI, FROM_HERE, 230 base::Bind(&PwgUtilityProcessHostClient::RunCallbackOnUIThread, this, 231 success)); 232} 233 234void PwgUtilityProcessHostClient::RunCallbackOnUIThread(bool success) { 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 236 if (!callback_.is_null()) { 237 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 238 base::Bind(callback_, success, 239 files_->GetPwgPath())); 240 callback_.Reset(); 241 } 242} 243 244class PWGRasterConverterImpl : public PWGRasterConverter { 245 public: 246 PWGRasterConverterImpl(); 247 248 virtual ~PWGRasterConverterImpl(); 249 250 virtual void Start(base::RefCountedMemory* data, 251 const printing::PdfRenderSettings& conversion_settings, 252 const printing::PwgRasterSettings& bitmap_settings, 253 const ResultCallback& callback) OVERRIDE; 254 255 private: 256 scoped_refptr<PwgUtilityProcessHostClient> utility_client_; 257 base::CancelableCallback<ResultCallback::RunType> callback_; 258 259 DISALLOW_COPY_AND_ASSIGN(PWGRasterConverterImpl); 260}; 261 262PWGRasterConverterImpl::PWGRasterConverterImpl() { 263} 264 265PWGRasterConverterImpl::~PWGRasterConverterImpl() { 266} 267 268void PWGRasterConverterImpl::Start( 269 base::RefCountedMemory* data, 270 const printing::PdfRenderSettings& conversion_settings, 271 const printing::PwgRasterSettings& bitmap_settings, 272 const ResultCallback& callback) { 273 // Rebind cancelable callback to avoid calling callback if 274 // PWGRasterConverterImpl is destroyed. 275 callback_.Reset(callback); 276 utility_client_ = 277 new PwgUtilityProcessHostClient(conversion_settings, bitmap_settings); 278 utility_client_->Convert(data, callback_.callback()); 279} 280 281} // namespace 282 283// static 284scoped_ptr<PWGRasterConverter> PWGRasterConverter::CreateDefault() { 285 return scoped_ptr<PWGRasterConverter>(new PWGRasterConverterImpl()); 286} 287 288} // namespace local_discovery 289