Index: chrome/browser/local_discovery/pwg_raster_converter.cc |
diff --git a/chrome/browser/local_discovery/pwg_raster_converter.cc b/chrome/browser/local_discovery/pwg_raster_converter.cc |
index cd50d95f03faebf7797602321002e96b39bcff8b..215cbee91ae575b5f2a032829c9ba825cc92470e 100644 |
--- a/chrome/browser/local_discovery/pwg_raster_converter.cc |
+++ b/chrome/browser/local_discovery/pwg_raster_converter.cc |
@@ -4,12 +4,245 @@ |
#include "chrome/browser/local_discovery/pwg_raster_converter.h" |
+#include "base/cancelable_callback.h" |
+#include "base/file_util.h" |
+#include "base/files/scoped_temp_dir.h" |
#include "base/logging.h" |
+#include "chrome/common/chrome_utility_messages.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/child_process_data.h" |
+#include "content/public/browser/utility_process_host.h" |
+#include "content/public/browser/utility_process_host_client.h" |
namespace local_discovery { |
namespace { |
+using content::BrowserThread; |
+ |
+class FileHandlers { |
+ public: |
+ FileHandlers() : pdf_file_(base::kInvalidPlatformFileValue), |
+ pwg_file_(base::kInvalidPlatformFileValue) { } |
+ |
+ ~FileHandlers() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ if (pdf_file_ != base::kInvalidPlatformFileValue) |
+ base::ClosePlatformFile(pdf_file_); |
+ if (pwg_file_ != base::kInvalidPlatformFileValue) |
+ base::ClosePlatformFile(pwg_file_); |
+ } |
+ |
+ void Init(base::RefCountedMemory* data); |
+ bool IsValid(); |
+ |
+ base::FilePath GetPwgPath() const { |
+ return temp_dir_.path().AppendASCII("output.pwg"); |
+ } |
+ |
+ base::FilePath GetPdfPath() const { |
+ return temp_dir_.path().AppendASCII("input.pdf"); |
+ } |
+ |
+ IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) { |
+ DCHECK_NE(pdf_file_, base::kInvalidPlatformFileValue); |
+ IPC::PlatformFileForTransit transit = |
+ IPC::GetFileHandleForProcess(pdf_file_, process, true); |
+ pdf_file_ = base::kInvalidPlatformFileValue; |
+ return transit; |
+ } |
+ |
+ IPC::PlatformFileForTransit GetPwgForProcess(base::ProcessHandle process) { |
+ DCHECK_NE(pwg_file_, base::kInvalidPlatformFileValue); |
+ IPC::PlatformFileForTransit transit = |
+ IPC::GetFileHandleForProcess(pwg_file_, process, true); |
+ pwg_file_ = base::kInvalidPlatformFileValue; |
+ return transit; |
+ } |
+ |
+ private: |
+ base::ScopedTempDir temp_dir_; |
+ base::PlatformFile pdf_file_; |
+ base::PlatformFile pwg_file_; |
+}; |
+ |
+void FileHandlers::Init(base::RefCountedMemory* data) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ |
+ if (!temp_dir_.CreateUniqueTempDir()) { |
+ return; |
+ } |
+ |
+ if (static_cast<int>(data->size()) != |
+ file_util::WriteFile(GetPdfPath(), |
+ reinterpret_cast<const char*>(data->front()), |
+ data->size())) { |
+ return; |
+ } |
+ |
+ // Reopen in read only mode. |
+ pdf_file_ = base::CreatePlatformFile(GetPdfPath(), base::PLATFORM_FILE_OPEN | |
+ base::PLATFORM_FILE_READ, |
+ NULL, NULL); |
+ pwg_file_ = base::CreatePlatformFile(GetPwgPath(), |
+ base::PLATFORM_FILE_CREATE_ALWAYS | |
+ base::PLATFORM_FILE_APPEND, NULL, NULL); |
+} |
+ |
+bool FileHandlers::IsValid() { |
+ return pdf_file_ != base::kInvalidPlatformFileValue && |
+ pwg_file_ != base::kInvalidPlatformFileValue; |
+} |
+ |
+// Converts PDF into PWG raster. |
+// Class uses 3 threads: UI, IO and FILE. |
+// Internal workflow is following: |
+// 1. Create instance on the UI thread. (files_, settings_,) |
+// 2. Create file on the FILE thread. |
+// 3. Start utility process and start conversion on the IO thread. |
+// 4. Run result callback on the UI thread. |
+// 5. Instance is destroyed from any thread that has the last reference. |
+// 6. FileHandlers destroyed on the FILE thread. |
+// This step posts |FileHandlers| to be destroyed on the FILE thread. |
+// All these steps work sequentially, so no data should be accessed |
+// simultaneously by several threads. |
+class PwgUtilityProcessHostClient : public content::UtilityProcessHostClient { |
+ public: |
+ explicit PwgUtilityProcessHostClient( |
+ const printing::PdfRenderSettings& settings); |
+ virtual ~PwgUtilityProcessHostClient(); |
+ |
+ void Convert(base::RefCountedMemory* data, |
+ const PWGRasterConverter::ResultCallback& callback); |
+ |
+ // UtilityProcessHostClient implementation. |
+ virtual void OnProcessCrashed(int exit_code); |
+ virtual bool OnMessageReceived(const IPC::Message& message); |
+ |
+ private: |
+ // Message handlers. |
+ void OnProcessStarted(); |
+ void OnSucceeded(); |
+ void OnFailed(); |
+ |
+ void RunCallback(bool success); |
+ |
+ void StartProcessOnIOThread(); |
+ |
+ void RunCallbackOnUIThread(bool success); |
+ void OnFilesReadyOnUIThread(); |
+ |
+ scoped_ptr<FileHandlers> files_; |
+ printing::PdfRenderSettings settings_; |
+ PWGRasterConverter::ResultCallback callback_; |
+ base::WeakPtr<content::UtilityProcessHost> utility_process_host_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(PwgUtilityProcessHostClient); |
+}; |
+ |
+PwgUtilityProcessHostClient::PwgUtilityProcessHostClient( |
+ const printing::PdfRenderSettings& settings) : settings_(settings) { |
+} |
+ |
+PwgUtilityProcessHostClient::~PwgUtilityProcessHostClient() { |
+ // Delete temp directory. |
+ BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, files_.release()); |
+} |
+ |
+void PwgUtilityProcessHostClient::Convert( |
+ base::RefCountedMemory* data, |
+ const PWGRasterConverter::ResultCallback& callback) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ callback_ = callback; |
+ CHECK(!files_); |
+ files_.reset(new FileHandlers()); |
+ BrowserThread::PostTaskAndReply( |
+ BrowserThread::FILE, FROM_HERE, |
+ base::Bind(&FileHandlers::Init, base::Unretained(files_.get()), data), |
+ base::Bind(&PwgUtilityProcessHostClient::OnFilesReadyOnUIThread, this)); |
+} |
+ |
+void PwgUtilityProcessHostClient::OnProcessCrashed(int exit_code) { |
+ OnFailed(); |
+} |
+ |
+bool PwgUtilityProcessHostClient::OnMessageReceived( |
+ const IPC::Message& message) { |
+ bool handled = true; |
+ IPC_BEGIN_MESSAGE_MAP(PwgUtilityProcessHostClient, message) |
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) |
+ IPC_MESSAGE_HANDLER( |
+ ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Succeeded, OnSucceeded) |
+ IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToPWGRaster_Failed, |
+ OnFailed) |
+ IPC_MESSAGE_UNHANDLED(handled = false) |
+ IPC_END_MESSAGE_MAP() |
+ return handled; |
+} |
+ |
+void PwgUtilityProcessHostClient::OnProcessStarted() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ if (!utility_process_host_) { |
+ RunCallbackOnUIThread(false); |
+ return; |
+ } |
+ |
+ base::ProcessHandle process = utility_process_host_->GetData().handle; |
+ utility_process_host_->Send( |
+ new ChromeUtilityMsg_RenderPDFPagesToPWGRaster( |
+ files_->GetPdfForProcess(process), |
+ settings_, |
+ files_->GetPwgForProcess(process))); |
+ utility_process_host_.reset(); |
Lei Zhang
2013/11/22 01:57:24
Actually, is this suppose to be there?
Vitaly Buka (NO REVIEWS)
2013/11/22 08:10:05
I guess it's safer. it's weak ptr, so it does not
|
+} |
+ |
+void PwgUtilityProcessHostClient::OnSucceeded() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ RunCallback(true); |
+} |
+ |
+void PwgUtilityProcessHostClient::OnFailed() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ RunCallback(false); |
+} |
+ |
+void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (!files_->IsValid()) { |
+ RunCallbackOnUIThread(false); |
+ return; |
+ } |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&PwgUtilityProcessHostClient::StartProcessOnIOThread, this)); |
+} |
+ |
+void PwgUtilityProcessHostClient::StartProcessOnIOThread() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ utility_process_host_ = |
+ content::UtilityProcessHost::Create( |
+ this, |
+ base::MessageLoop::current()->message_loop_proxy())->AsWeakPtr(); |
+ utility_process_host_->Send(new ChromeUtilityMsg_StartupPing); |
+} |
+ |
+void PwgUtilityProcessHostClient::RunCallback(bool success) { |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&PwgUtilityProcessHostClient::RunCallbackOnUIThread, this, |
+ success)); |
+} |
+ |
+void PwgUtilityProcessHostClient::RunCallbackOnUIThread(bool success) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (!callback_.is_null()) { |
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
+ base::Bind(callback_, success, |
+ files_->GetPwgPath())); |
+ callback_.Reset(); |
+ } |
+} |
+ |
class PWGRasterConverterImpl : public PWGRasterConverter { |
public: |
PWGRasterConverterImpl(); |
@@ -20,6 +253,9 @@ class PWGRasterConverterImpl : public PWGRasterConverter { |
const printing::PdfRenderSettings& conversion_settings, |
const ResultCallback& callback) OVERRIDE; |
private: |
+ scoped_refptr<PwgUtilityProcessHostClient> utility_client_; |
+ base::CancelableCallback<ResultCallback::RunType> callback_; |
+ |
DISALLOW_COPY_AND_ASSIGN(PWGRasterConverterImpl); |
}; |
@@ -33,7 +269,11 @@ void PWGRasterConverterImpl::Start( |
base::RefCountedMemory* data, |
const printing::PdfRenderSettings& conversion_settings, |
const ResultCallback& callback) { |
- NOTIMPLEMENTED(); |
+ // Rebind cancelable callback to avoid calling callback if |
+ // PWGRasterConverterImpl is destroyed. |
+ callback_.Reset(callback); |
+ utility_client_ = new PwgUtilityProcessHostClient(conversion_settings); |
+ utility_client_->Convert(data, callback_.callback()); |
} |
} // namespace |