Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / printing / print_job.cc
index 4a58440..0998611 100644 (file)
 #include "printing/printed_document.h"
 #include "printing/printed_page.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/printing/pdf_to_emf_converter.h"
+#include "printing/pdf_render_settings.h"
+#endif
+
 using base::TimeDelta;
 
 namespace {
@@ -32,29 +37,25 @@ void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner,
 namespace printing {
 
 PrintJob::PrintJob()
-    : ui_message_loop_(base::MessageLoop::current()),
-      source_(NULL),
+    : source_(NULL),
       worker_(),
       settings_(),
       is_job_pending_(false),
       is_canceling_(false),
       quit_factory_(this) {
-  DCHECK(ui_message_loop_);
   // This is normally a UI message loop, but in unit tests, the message loop is
   // of the 'default' type.
   DCHECK(base::MessageLoopForUI::IsCurrent() ||
-         ui_message_loop_->type() == base::MessageLoop::TYPE_DEFAULT);
-  ui_message_loop_->AddDestructionObserver(this);
+         base::MessageLoop::current()->type() ==
+             base::MessageLoop::TYPE_DEFAULT);
 }
 
 PrintJob::~PrintJob() {
-  ui_message_loop_->RemoveDestructionObserver(this);
   // The job should be finished (or at least canceled) when it is destroyed.
   DCHECK(!is_job_pending_);
   DCHECK(!is_canceling_);
-  if (worker_.get())
-    DCHECK(worker_->message_loop() == NULL);
-  DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
+  DCHECK(!worker_ || !worker_->IsRunning());
+  DCHECK(RunsTasksOnCurrentThread());
 }
 
 void PrintJob::Initialize(PrintJobWorkerOwner* job,
@@ -85,7 +86,7 @@ void PrintJob::Initialize(PrintJobWorkerOwner* job,
 void PrintJob::Observe(int type,
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) {
-  DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
+  DCHECK(RunsTasksOnCurrentThread());
   switch (type) {
     case chrome::NOTIFICATION_PRINT_JOB_EVENT: {
       OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
@@ -107,10 +108,6 @@ PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) {
   return NULL;
 }
 
-base::MessageLoop* PrintJob::message_loop() {
-  return ui_message_loop_;
-}
-
 const PrintSettings& PrintJob::settings() const {
   return settings_;
 }
@@ -122,23 +119,20 @@ int PrintJob::cookie() const {
   return document_->cookie();
 }
 
-void PrintJob::WillDestroyCurrentMessageLoop() {
-  NOTREACHED();
-}
-
 void PrintJob::StartPrinting() {
-  DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
-  DCHECK(worker_->message_loop());
+  DCHECK(RunsTasksOnCurrentThread());
+  DCHECK(worker_->IsRunning());
   DCHECK(!is_job_pending_);
-  if (!worker_->message_loop() || is_job_pending_)
+  if (!worker_->IsRunning() || is_job_pending_)
     return;
 
   // Real work is done in PrintJobWorker::StartPrinting().
-  worker_->message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&HoldRefCallback, make_scoped_refptr(this),
-                 base::Bind(&PrintJobWorker::StartPrinting,
-                            base::Unretained(worker_.get()), document_)));
+  worker_->PostTask(FROM_HERE,
+                    base::Bind(&HoldRefCallback,
+                               make_scoped_refptr(this),
+                               base::Bind(&PrintJobWorker::StartPrinting,
+                                          base::Unretained(worker_.get()),
+                                          document_)));
   // Set the flag right now.
   is_job_pending_ = true;
 
@@ -152,7 +146,7 @@ void PrintJob::StartPrinting() {
 }
 
 void PrintJob::Stop() {
-  DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
+  DCHECK(RunsTasksOnCurrentThread());
 
   if (quit_factory_.HasWeakPtrs()) {
     // In case we're running a nested message loop to wait for a job to finish,
@@ -164,7 +158,7 @@ void PrintJob::Stop() {
   // Be sure to live long enough.
   scoped_refptr<PrintJob> handle(this);
 
-  if (worker_->message_loop()) {
+  if (worker_->IsRunning()) {
     ControlledWorkerShutdown();
   } else {
     // Flush the cached document.
@@ -180,10 +174,8 @@ void PrintJob::Cancel() {
   // Be sure to live long enough.
   scoped_refptr<PrintJob> handle(this);
 
-  DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
-  base::MessageLoop* worker_loop =
-      worker_.get() ? worker_->message_loop() : NULL;
-  if (worker_loop) {
+  DCHECK(RunsTasksOnCurrentThread());
+  if (worker_ && worker_->IsRunning()) {
     // Call this right now so it renders the context invalid. Do not use
     // InvokeLater since it would take too much time.
     worker_->Cancel();
@@ -227,6 +219,103 @@ PrintedDocument* PrintJob::document() const {
   return document_.get();
 }
 
+#if defined(OS_WIN)
+
+class PrintJob::PdfToEmfState {
+ public:
+  PdfToEmfState(const gfx::Size& page_size, const gfx::Rect& content_area)
+      : page_count_(0),
+        current_page_(0),
+        pages_in_progress_(0),
+        page_size_(page_size),
+        content_area_(content_area),
+        converter_(PdfToEmfConverter::CreateDefault()) {}
+
+  void Start(const scoped_refptr<base::RefCountedMemory>& data,
+             const PdfRenderSettings& conversion_settings,
+             const PdfToEmfConverter::StartCallback& start_callback) {
+    converter_->Start(data, conversion_settings, start_callback);
+  }
+
+  void GetMorePages(
+      const PdfToEmfConverter::GetPageCallback& get_page_callback) {
+    const int kMaxNumberOfTempFilesPerDocument = 3;
+    while (pages_in_progress_ < kMaxNumberOfTempFilesPerDocument &&
+           current_page_ < page_count_) {
+      ++pages_in_progress_;
+      converter_->GetPage(current_page_++, get_page_callback);
+    }
+  }
+
+  void OnPageProcessed(
+      const PdfToEmfConverter::GetPageCallback& get_page_callback) {
+    --pages_in_progress_;
+    GetMorePages(get_page_callback);
+    // Release converter if we don't need this any more.
+    if (!pages_in_progress_ && current_page_ >= page_count_)
+      converter_.reset();
+  }
+
+  void set_page_count(int page_count) { page_count_ = page_count; }
+  gfx::Size page_size() const { return page_size_; }
+  gfx::Rect content_area() const { return content_area_; }
+
+ private:
+  int page_count_;
+  int current_page_;
+  int pages_in_progress_;
+  gfx::Size page_size_;
+  gfx::Rect content_area_;
+  scoped_ptr<PdfToEmfConverter> converter_;
+};
+
+void PrintJob::StartPdfToEmfConversion(
+    const scoped_refptr<base::RefCountedMemory>& bytes,
+    const gfx::Size& page_size,
+    const gfx::Rect& content_area) {
+  DCHECK(!ptd_to_emf_state_.get());
+  ptd_to_emf_state_.reset(new PdfToEmfState(page_size, content_area));
+  const int kPrinterDpi = settings().dpi();
+  ptd_to_emf_state_->Start(
+      bytes,
+      printing::PdfRenderSettings(content_area, kPrinterDpi, true),
+      base::Bind(&PrintJob::OnPdfToEmfStarted, this));
+}
+
+void PrintJob::OnPdfToEmfStarted(int page_count) {
+  if (page_count <= 0) {
+    ptd_to_emf_state_.reset();
+    Cancel();
+    return;
+  }
+  ptd_to_emf_state_->set_page_count(page_count);
+  ptd_to_emf_state_->GetMorePages(
+      base::Bind(&PrintJob::OnPdfToEmfPageConverted, this));
+}
+
+void PrintJob::OnPdfToEmfPageConverted(int page_number,
+                                       double scale_factor,
+                                       scoped_ptr<MetafilePlayer> emf) {
+  DCHECK(ptd_to_emf_state_);
+  if (!document_.get() || !emf) {
+    ptd_to_emf_state_.reset();
+    Cancel();
+    return;
+  }
+
+  // Update the rendered document. It will send notifications to the listener.
+  document_->SetPage(page_number,
+                     emf.Pass(),
+                     scale_factor,
+                     ptd_to_emf_state_->page_size(),
+                     ptd_to_emf_state_->content_area());
+
+  ptd_to_emf_state_->GetMorePages(
+      base::Bind(&PrintJob::OnPdfToEmfPageConverted, this));
+}
+
+#endif  // OS_WIN
+
 void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
   if (document_.get() == new_document)
     return;
@@ -237,14 +326,15 @@ void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
     settings_ = document_->settings();
   }
 
-  if (worker_.get() && worker_->message_loop()) {
+  if (worker_) {
     DCHECK(!is_job_pending_);
     // Sync the document with the worker.
-    worker_->message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&HoldRefCallback, make_scoped_refptr(this),
-                   base::Bind(&PrintJobWorker::OnDocumentChanged,
-                              base::Unretained(worker_.get()), document_)));
+    worker_->PostTask(FROM_HERE,
+                      base::Bind(&HoldRefCallback,
+                                 make_scoped_refptr(this),
+                                 base::Bind(&PrintJobWorker::OnDocumentChanged,
+                                            base::Unretained(worker_.get()),
+                                            document_)));
   }
 }
 
@@ -264,7 +354,6 @@ void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
     }
     case JobEventDetails::NEW_DOC:
     case JobEventDetails::NEW_PAGE:
-    case JobEventDetails::PAGE_DONE:
     case JobEventDetails::JOB_DONE:
     case JobEventDetails::ALL_PAGES_REQUESTED: {
       // Don't care.
@@ -276,6 +365,12 @@ void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
           FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this));
       break;
     }
+    case JobEventDetails::PAGE_DONE:
+#if defined(OS_WIN)
+      ptd_to_emf_state_->OnPageProcessed(
+          base::Bind(&PrintJob::OnPdfToEmfPageConverted, this));
+#endif  // OS_WIN
+      break;
     default: {
       NOTREACHED();
       break;
@@ -300,7 +395,7 @@ void PrintJob::OnDocumentDone() {
 }
 
 void PrintJob::ControlledWorkerShutdown() {
-  DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
+  DCHECK(RunsTasksOnCurrentThread());
 
   // The deadlock this code works around is specific to window messaging on
   // Windows, so we aren't likely to need it on any other platforms.