Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/printing/pdf_to_emf_converter.h" | 5 #include "chrome/browser/printing/pdf_to_emf_converter.h" |
| 6 | 6 |
| 7 #include "base/bind_helpers.h" | 7 #include "base/bind_helpers.h" |
| 8 #include "base/cancelable_callback.h" | 8 #include "base/cancelable_callback.h" |
| 9 #include "base/files/file.h" | 9 #include "base/files/file.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 11 #include "base/files/scoped_temp_dir.h" | 11 #include "base/files/scoped_temp_dir.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "chrome/common/chrome_utility_messages.h" | 13 #include "chrome/common/chrome_utility_messages.h" |
| 14 #include "chrome/common/chrome_utility_printing_messages.h" | 14 #include "chrome/common/chrome_utility_printing_messages.h" |
| 15 #include "content/public/browser/browser_thread.h" | 15 #include "content/public/browser/browser_thread.h" |
| 16 #include "content/public/browser/child_process_data.h" | 16 #include "content/public/browser/child_process_data.h" |
| 17 #include "content/public/browser/utility_process_host.h" | 17 #include "content/public/browser/utility_process_host.h" |
| 18 #include "content/public/browser/utility_process_host_client.h" | 18 #include "content/public/browser/utility_process_host_client.h" |
| 19 #include "printing/emf_win.h" | |
| 19 #include "printing/page_range.h" | 20 #include "printing/page_range.h" |
| 20 #include "printing/pdf_render_settings.h" | 21 #include "printing/pdf_render_settings.h" |
| 21 | 22 |
| 22 namespace printing { | 23 namespace printing { |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 | 26 |
| 26 using content::BrowserThread; | 27 using content::BrowserThread; |
| 27 | 28 |
| 28 class FileHandlers { | 29 class FileHandlers |
| 30 : public base::RefCountedThreadSafe<FileHandlers, | |
| 31 BrowserThread::DeleteOnFileThread> { | |
| 29 public: | 32 public: |
| 30 FileHandlers() {} | 33 FileHandlers() {} |
| 31 | 34 |
| 32 ~FileHandlers() { | |
| 33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 34 } | |
| 35 | |
| 36 void Init(base::RefCountedMemory* data); | 35 void Init(base::RefCountedMemory* data); |
| 37 bool IsValid(); | 36 bool IsValid(); |
| 38 | 37 |
| 39 base::FilePath GetEmfPath() const { | 38 base::FilePath GetEmfPath() const { |
| 40 return temp_dir_.path().AppendASCII("output.emf"); | 39 return temp_dir_.path().AppendASCII("output.emf"); |
| 41 } | 40 } |
| 42 | 41 |
| 42 base::FilePath GetEmfPagePath(int page_number) const { | |
| 43 return GetEmfPath().InsertBeforeExtensionASCII( | |
| 44 base::StringPrintf(".%d", page_number)); | |
| 45 } | |
| 46 | |
| 43 base::FilePath GetPdfPath() const { | 47 base::FilePath GetPdfPath() const { |
| 44 return temp_dir_.path().AppendASCII("input.pdf"); | 48 return temp_dir_.path().AppendASCII("input.pdf"); |
| 45 } | 49 } |
| 46 | 50 |
| 47 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) { | 51 IPC::PlatformFileForTransit GetPdfForProcess(base::ProcessHandle process) { |
| 48 DCHECK(pdf_file_.IsValid()); | 52 DCHECK(pdf_file_.IsValid()); |
| 49 IPC::PlatformFileForTransit transit = | 53 IPC::PlatformFileForTransit transit = |
| 50 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process); | 54 IPC::TakeFileHandleForProcess(pdf_file_.Pass(), process); |
| 51 return transit; | 55 return transit; |
| 52 } | 56 } |
| 53 | 57 |
| 54 const base::FilePath& GetBasePath() const { | 58 const base::FilePath& GetBasePath() const { |
| 55 return temp_dir_.path(); | 59 return temp_dir_.path(); |
| 56 } | 60 } |
| 57 | 61 |
| 58 private: | 62 private: |
| 63 friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>; | |
| 64 friend class base::DeleteHelper<FileHandlers>; | |
| 65 | |
| 66 ~FileHandlers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); } | |
| 67 | |
| 59 base::ScopedTempDir temp_dir_; | 68 base::ScopedTempDir temp_dir_; |
| 60 base::File pdf_file_; | 69 base::File pdf_file_; |
| 61 }; | 70 }; |
| 62 | 71 |
| 63 void FileHandlers::Init(base::RefCountedMemory* data) { | 72 void FileHandlers::Init(base::RefCountedMemory* data) { |
| 64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 65 | 74 |
| 66 if (!temp_dir_.CreateUniqueTempDir()) { | 75 if (!temp_dir_.CreateUniqueTempDir()) { |
| 67 return; | 76 return; |
| 68 } | 77 } |
| 69 | 78 |
| 79 pdf_file_.Initialize(GetPdfPath(), | |
| 80 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | | |
| 81 base::File::FLAG_READ | | |
| 82 base::File::FLAG_DELETE_ON_CLOSE); | |
| 70 if (static_cast<int>(data->size()) != | 83 if (static_cast<int>(data->size()) != |
| 71 base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) { | 84 pdf_file_.WriteAtCurrentPos(data->front_as<char>(), data->size())) { |
| 85 pdf_file_.Close(); | |
| 72 return; | 86 return; |
| 73 } | 87 } |
| 74 | 88 pdf_file_.Seek(base::File::FROM_BEGIN, 0); |
| 75 // Reopen in read only mode. | 89 pdf_file_.Flush(); |
|
scottmg
2014/09/08 19:06:11
I'm not sure why it was re-opened readonly before,
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:57
I see no reason why it's bad, because target proce
| |
| 76 pdf_file_.Initialize(GetPdfPath(), | |
| 77 base::File::FLAG_OPEN | base::File::FLAG_READ); | |
| 78 } | 90 } |
| 79 | 91 |
| 80 bool FileHandlers::IsValid() { | 92 bool FileHandlers::IsValid() { |
| 81 return pdf_file_.IsValid(); | 93 return pdf_file_.IsValid(); |
| 82 } | 94 } |
| 83 | 95 |
| 96 // Modification of Emf to keep references to |FileHandlers|. | |
| 97 // |FileHandlers| must be deleted after the last metafile is closed because | |
| 98 // Emf holds files locked. | |
| 99 // Ideally we want to use FLAG_DELETE_ON_CLOSE, but it requires large changes. | |
| 100 // It's going to be done for crbug.com/408184 | |
| 101 class TempEmf : public Emf { | |
| 102 public: | |
| 103 explicit TempEmf(const scoped_refptr<FileHandlers>& files) : files_(files) {} | |
| 104 | |
| 105 virtual ~TempEmf() {}; | |
|
scottmg
2014/09/08 19:06:10
no ;
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:58
Done.
| |
| 106 | |
| 107 virtual bool SafePlayback(HDC hdc) const OVERRIDE { | |
| 108 bool result = Emf::SafePlayback(hdc); | |
| 109 TempEmf* this_mutable = const_cast<TempEmf*>(this); | |
| 110 // TODO(vitalybuka): Fix destruction of metafiles. For some reasons | |
| 111 // instances of Emf are not deleted. crbug.com/411683 | |
|
scottmg
2014/09/08 19:06:11
that seems pretty worrying, do you have any insigh
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:57
Yes PrintedDocument. I have no more details yet, b
| |
| 112 // |files_| must be released as soon as possible to guaranty deletion. | |
|
scottmg
2014/09/08 19:06:10
nit; guaranty -> guarantee
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:58
Done.
| |
| 113 // It's know that that this Emf file is going to be played just once to | |
|
scottmg
2014/09/08 19:06:10
nit; "know that that" -> "known that"
Vitaly Buka (NO REVIEWS)
2014/09/08 19:19:58
Done.
| |
| 114 // a printer. So just release files here. | |
| 115 this_mutable->Close(); | |
| 116 this_mutable->files_ = NULL; | |
| 117 return result; | |
| 118 } | |
| 119 | |
| 120 private: | |
| 121 scoped_refptr<FileHandlers> files_; | |
| 122 DISALLOW_COPY_AND_ASSIGN(TempEmf); | |
| 123 }; | |
| 124 | |
| 84 // Converts PDF into EMF. | 125 // Converts PDF into EMF. |
| 85 // Class uses 3 threads: UI, IO and FILE. | 126 // Class uses 3 threads: UI, IO and FILE. |
| 86 // Internal workflow is following: | 127 // Internal workflow is following: |
| 87 // 1. Create instance on the UI thread. (files_, settings_,) | 128 // 1. Create instance on the UI thread. (files_, settings_,) |
| 88 // 2. Create file on the FILE thread. | 129 // 2. Create file on the FILE thread. |
| 89 // 3. Start utility process and start conversion on the IO thread. | 130 // 3. Start utility process and start conversion on the IO thread. |
| 90 // 4. Run result callback on the UI thread. | 131 // 4. Run result callback on the UI thread. |
| 91 // 5. Instance is destroyed from any thread that has the last reference. | 132 // 5. Instance is destroyed from any thread that has the last reference. |
| 92 // 6. FileHandlers destroyed on the FILE thread. | 133 // 6. FileHandlers destroyed on the FILE thread. |
| 93 // This step posts |FileHandlers| to be destroyed on the FILE thread. | 134 // This step posts |FileHandlers| to be destroyed on the FILE thread. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 118 void RunCallback(const std::vector<printing::PageRange>& page_ranges, | 159 void RunCallback(const std::vector<printing::PageRange>& page_ranges, |
| 119 double scale_factor); | 160 double scale_factor); |
| 120 | 161 |
| 121 void StartProcessOnIOThread(); | 162 void StartProcessOnIOThread(); |
| 122 | 163 |
| 123 void RunCallbackOnUIThread( | 164 void RunCallbackOnUIThread( |
| 124 const std::vector<printing::PageRange>& page_ranges, | 165 const std::vector<printing::PageRange>& page_ranges, |
| 125 double scale_factor); | 166 double scale_factor); |
| 126 void OnFilesReadyOnUIThread(); | 167 void OnFilesReadyOnUIThread(); |
| 127 | 168 |
| 128 scoped_ptr<FileHandlers, BrowserThread::DeleteOnFileThread> files_; | 169 scoped_refptr<FileHandlers> files_; |
| 129 printing::PdfRenderSettings settings_; | 170 printing::PdfRenderSettings settings_; |
| 130 PdfToEmfConverter::ResultCallback callback_; | 171 PdfToEmfConverter::ResultCallback callback_; |
| 131 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; | 172 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; |
| 132 | 173 |
| 133 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); | 174 DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); |
| 134 }; | 175 }; |
| 135 | 176 |
| 136 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( | 177 PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( |
| 137 const printing::PdfRenderSettings& settings) | 178 const printing::PdfRenderSettings& settings) |
| 138 : settings_(settings) {} | 179 : settings_(settings) {} |
| 139 | 180 |
| 140 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { | 181 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { |
| 141 } | 182 } |
| 142 | 183 |
| 143 void PdfToEmfUtilityProcessHostClient::Convert( | 184 void PdfToEmfUtilityProcessHostClient::Convert( |
| 144 base::RefCountedMemory* data, | 185 base::RefCountedMemory* data, |
| 145 const PdfToEmfConverter::ResultCallback& callback) { | 186 const PdfToEmfConverter::ResultCallback& callback) { |
| 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 147 callback_ = callback; | 188 callback_ = callback; |
| 148 CHECK(!files_); | 189 CHECK(!files_.get()); |
| 149 files_.reset(new FileHandlers()); | 190 files_ = new FileHandlers(); |
| 150 BrowserThread::PostTaskAndReply( | 191 BrowserThread::PostTaskAndReply( |
| 151 BrowserThread::FILE, | 192 BrowserThread::FILE, |
| 152 FROM_HERE, | 193 FROM_HERE, |
| 153 base::Bind(&FileHandlers::Init, | 194 base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)), |
| 154 base::Unretained(files_.get()), | |
| 155 make_scoped_refptr(data)), | |
| 156 base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread, | 195 base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread, |
| 157 this)); | 196 this)); |
| 158 } | 197 } |
| 159 | 198 |
| 160 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { | 199 void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { |
| 161 OnFailed(); | 200 OnFailed(); |
| 162 } | 201 } |
| 163 | 202 |
| 164 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( | 203 bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( |
| 165 const IPC::Message& message) { | 204 const IPC::Message& message) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread, | 278 base::Bind(&PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread, |
| 240 this, | 279 this, |
| 241 page_ranges, | 280 page_ranges, |
| 242 scale_factor)); | 281 scale_factor)); |
| 243 } | 282 } |
| 244 | 283 |
| 245 void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread( | 284 void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread( |
| 246 const std::vector<printing::PageRange>& page_ranges, | 285 const std::vector<printing::PageRange>& page_ranges, |
| 247 double scale_factor) { | 286 double scale_factor) { |
| 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 249 std::vector<base::FilePath> page_filenames; | 288 ScopedVector<Metafile> pages; |
| 250 std::vector<printing::PageRange>::const_iterator iter; | 289 std::vector<printing::PageRange>::const_iterator iter; |
| 251 for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) { | 290 for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) { |
| 252 for (int page_number = iter->from; page_number <= iter->to; ++page_number) { | 291 for (int page_number = iter->from; page_number <= iter->to; ++page_number) { |
| 253 page_filenames.push_back(files_->GetEmfPath().InsertBeforeExtensionASCII( | 292 scoped_ptr<TempEmf> metafile(new TempEmf(files_)); |
| 254 base::StringPrintf(".%d", page_number))); | 293 if (!metafile->InitFromFile(files_->GetEmfPagePath(page_number))) { |
| 294 NOTREACHED() << "Invalid metafile"; | |
| 295 metafile.reset(); | |
| 296 } | |
| 297 pages.push_back(metafile.release()); | |
| 255 } | 298 } |
| 256 } | 299 } |
| 300 files_ = NULL; | |
| 257 if (!callback_.is_null()) { | 301 if (!callback_.is_null()) { |
| 258 BrowserThread::PostTask( | 302 callback_.Run(scale_factor, &pages); |
| 259 BrowserThread::UI, | |
| 260 FROM_HERE, | |
| 261 base::Bind(callback_, scale_factor, page_filenames)); | |
| 262 callback_.Reset(); | 303 callback_.Reset(); |
| 263 } | 304 } |
| 264 } | 305 } |
| 265 | 306 |
| 266 class PdfToEmfConverterImpl : public PdfToEmfConverter { | 307 class PdfToEmfConverterImpl : public PdfToEmfConverter { |
| 267 public: | 308 public: |
| 268 PdfToEmfConverterImpl(); | 309 PdfToEmfConverterImpl(); |
| 269 | 310 |
| 270 virtual ~PdfToEmfConverterImpl(); | 311 virtual ~PdfToEmfConverterImpl(); |
| 271 | 312 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 298 } | 339 } |
| 299 | 340 |
| 300 } // namespace | 341 } // namespace |
| 301 | 342 |
| 302 // static | 343 // static |
| 303 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { | 344 scoped_ptr<PdfToEmfConverter> PdfToEmfConverter::CreateDefault() { |
| 304 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); | 345 return scoped_ptr<PdfToEmfConverter>(new PdfToEmfConverterImpl()); |
| 305 } | 346 } |
| 306 | 347 |
| 307 } // namespace printing | 348 } // namespace printing |
| OLD | NEW |