Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / printing / pdf_to_emf_converter.cc
index 21800ee..5c07d96 100644 (file)
@@ -16,6 +16,7 @@
 #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"
+#include "printing/emf_win.h"
 #include "printing/page_range.h"
 #include "printing/pdf_render_settings.h"
 
@@ -25,14 +26,12 @@ namespace {
 
 using content::BrowserThread;
 
-class FileHandlers {
+class FileHandlers
+    : public base::RefCountedThreadSafe<FileHandlers,
+                                        BrowserThread::DeleteOnFileThread> {
  public:
   FileHandlers() {}
 
-  ~FileHandlers() {
-    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-  }
-
   void Init(base::RefCountedMemory* data);
   bool IsValid();
 
@@ -40,6 +39,11 @@ class FileHandlers {
     return temp_dir_.path().AppendASCII("output.emf");
   }
 
+  base::FilePath GetEmfPagePath(int page_number) const {
+    return GetEmfPath().InsertBeforeExtensionASCII(
+        base::StringPrintf(".%d", page_number));
+  }
+
   base::FilePath GetPdfPath() const {
     return temp_dir_.path().AppendASCII("input.pdf");
   }
@@ -56,6 +60,11 @@ class FileHandlers {
   }
 
  private:
+  friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
+  friend class base::DeleteHelper<FileHandlers>;
+
+  ~FileHandlers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); }
+
   base::ScopedTempDir temp_dir_;
   base::File pdf_file_;
 };
@@ -67,20 +76,51 @@ void FileHandlers::Init(base::RefCountedMemory* data) {
     return;
   }
 
+  pdf_file_.Initialize(GetPdfPath(),
+                       base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
+                           base::File::FLAG_READ |
+                           base::File::FLAG_DELETE_ON_CLOSE);
   if (static_cast<int>(data->size()) !=
-      base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) {
+      pdf_file_.WriteAtCurrentPos(data->front_as<char>(), data->size())) {
+    pdf_file_.Close();
     return;
   }
-
-  // Reopen in read only mode.
-  pdf_file_.Initialize(GetPdfPath(),
-                       base::File::FLAG_OPEN | base::File::FLAG_READ);
+  pdf_file_.Seek(base::File::FROM_BEGIN, 0);
+  pdf_file_.Flush();
 }
 
 bool FileHandlers::IsValid() {
   return pdf_file_.IsValid();
 }
 
+// Modification of Emf to keep references to |FileHandlers|.
+// |FileHandlers| must be deleted after the last metafile is closed because
+// Emf holds files locked.
+// Ideally we want to use FLAG_DELETE_ON_CLOSE, but it requires large changes.
+// It's going to be done for crbug.com/408184
+class TempEmf : public Emf {
+ public:
+  explicit TempEmf(const scoped_refptr<FileHandlers>& files) : files_(files) {}
+  virtual ~TempEmf() {}
+
+  virtual bool SafePlayback(HDC hdc) const OVERRIDE {
+    bool result = Emf::SafePlayback(hdc);
+    TempEmf* this_mutable = const_cast<TempEmf*>(this);
+    // TODO(vitalybuka): Fix destruction of metafiles. For some reasons
+    // instances of Emf are not deleted. crbug.com/411683
+    // |files_| must be released as soon as possible to guarantee deletion.
+    // It's know that this Emf file is going to be played just once to
+    // a printer. So just release files here.
+    this_mutable->Close();
+    this_mutable->files_ = NULL;
+    return result;
+  }
+
+ private:
+  scoped_refptr<FileHandlers> files_;
+  DISALLOW_COPY_AND_ASSIGN(TempEmf);
+};
+
 // Converts PDF into EMF.
 // Class uses 3 threads: UI, IO and FILE.
 // Internal workflow is following:
@@ -125,7 +165,7 @@ class PdfToEmfUtilityProcessHostClient
       double scale_factor);
   void OnFilesReadyOnUIThread();
 
-  scoped_ptr<FileHandlers> files_;
+  scoped_refptr<FileHandlers> files_;
   printing::PdfRenderSettings settings_;
   PdfToEmfConverter::ResultCallback callback_;
   base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
@@ -138,8 +178,6 @@ PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
     : settings_(settings) {}
 
 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
-  // Delete temp directory.
-  BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, files_.release());
 }
 
 void PdfToEmfUtilityProcessHostClient::Convert(
@@ -147,14 +185,12 @@ void PdfToEmfUtilityProcessHostClient::Convert(
     const PdfToEmfConverter::ResultCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   callback_ = callback;
-  CHECK(!files_);
-  files_.reset(new FileHandlers());
+  CHECK(!files_.get());
+  files_ = new FileHandlers();
   BrowserThread::PostTaskAndReply(
       BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(&FileHandlers::Init,
-                 base::Unretained(files_.get()),
-                 make_scoped_refptr(data)),
+      base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)),
       base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread,
                  this));
 }
@@ -248,19 +284,21 @@ void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread(
     const std::vector<printing::PageRange>& page_ranges,
     double scale_factor) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  std::vector<base::FilePath> page_filenames;
+  ScopedVector<Metafile> pages;
   std::vector<printing::PageRange>::const_iterator iter;
   for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) {
     for (int page_number = iter->from; page_number <= iter->to; ++page_number) {
-      page_filenames.push_back(files_->GetEmfPath().InsertBeforeExtensionASCII(
-          base::StringPrintf(".%d", page_number)));
+      scoped_ptr<TempEmf> metafile(new TempEmf(files_));
+      if (!metafile->InitFromFile(files_->GetEmfPagePath(page_number))) {
+        NOTREACHED() << "Invalid metafile";
+        metafile.reset();
+      }
+      pages.push_back(metafile.release());
     }
   }
+  files_ = NULL;
   if (!callback_.is_null()) {
-    BrowserThread::PostTask(
-        BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(callback_, scale_factor, page_filenames));
+    callback_.Run(scale_factor, &pages);
     callback_.Reset();
   }
 }