Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(488)

Side by Side Diff: chrome/browser/printing/print_job.cc

Issue 2271743003: Win: Fix printing selected pages with native dialog. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: git cl format Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/printing/print_job.h ('k') | chrome/browser/printing/print_view_manager_base.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/print_job.h" 5 #include "chrome/browser/printing/print_job.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility>
8 9
9 #include "base/bind.h" 10 #include "base/bind.h"
10 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
11 #include "base/location.h" 12 #include "base/location.h"
13 #include "base/memory/ptr_util.h"
12 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h" 15 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
15 #include "base/threading/thread_restrictions.h" 17 #include "base/threading/thread_restrictions.h"
16 #include "base/threading/thread_task_runner_handle.h" 18 #include "base/threading/thread_task_runner_handle.h"
17 #include "base/threading/worker_pool.h" 19 #include "base/threading/worker_pool.h"
18 #include "build/build_config.h" 20 #include "build/build_config.h"
19 #include "chrome/browser/chrome_notification_types.h" 21 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/printing/print_job_worker.h" 22 #include "chrome/browser/printing/print_job_worker.h"
21 #include "content/public/browser/browser_thread.h" 23 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/notification_service.h" 24 #include "content/public/browser/notification_service.h"
23 #include "printing/printed_document.h" 25 #include "printing/printed_document.h"
24 #include "printing/printed_page.h" 26 #include "printing/printed_page.h"
25 27
26 #if defined(OS_WIN) 28 #if defined(OS_WIN)
27 #include "chrome/browser/printing/pdf_to_emf_converter.h" 29 #include "chrome/browser/printing/pdf_to_emf_converter.h"
28 #include "printing/pdf_render_settings.h" 30 #include "printing/pdf_render_settings.h"
29 #endif 31 #endif
30 32
31 using base::TimeDelta; 33 using base::TimeDelta;
32 34
35 namespace printing {
36
33 namespace { 37 namespace {
34 38
35 // Helper function to ensure |owner| is valid until at least |callback| returns. 39 // Helper function to ensure |owner| is valid until at least |callback| returns.
36 void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner, 40 void HoldRefCallback(const scoped_refptr<PrintJobWorkerOwner>& owner,
37 const base::Closure& callback) { 41 const base::Closure& callback) {
38 callback.Run(); 42 callback.Run();
39 } 43 }
40 44
41 } // namespace 45 } // namespace
42 46
43 namespace printing {
44
45 PrintJob::PrintJob() 47 PrintJob::PrintJob()
46 : source_(NULL), 48 : source_(nullptr),
47 worker_(),
48 settings_(),
49 is_job_pending_(false), 49 is_job_pending_(false),
50 is_canceling_(false), 50 is_canceling_(false),
51 quit_factory_(this) { 51 quit_factory_(this) {
52 // This is normally a UI message loop, but in unit tests, the message loop is 52 // This is normally a UI message loop, but in unit tests, the message loop is
53 // of the 'default' type. 53 // of the 'default' type.
54 DCHECK(base::MessageLoopForUI::IsCurrent() || 54 DCHECK(base::MessageLoopForUI::IsCurrent() ||
55 base::MessageLoop::current()->type() == 55 base::MessageLoop::current()->type() ==
56 base::MessageLoop::TYPE_DEFAULT); 56 base::MessageLoop::TYPE_DEFAULT);
57 } 57 }
58 58
59 PrintJob::~PrintJob() { 59 PrintJob::~PrintJob() {
60 // The job should be finished (or at least canceled) when it is destroyed. 60 // The job should be finished (or at least canceled) when it is destroyed.
61 DCHECK(!is_job_pending_); 61 DCHECK(!is_job_pending_);
62 DCHECK(!is_canceling_); 62 DCHECK(!is_canceling_);
63 DCHECK(!worker_ || !worker_->IsRunning()); 63 DCHECK(!worker_ || !worker_->IsRunning());
64 DCHECK(RunsTasksOnCurrentThread()); 64 DCHECK(RunsTasksOnCurrentThread());
65 } 65 }
66 66
67 void PrintJob::Initialize(PrintJobWorkerOwner* job, 67 void PrintJob::Initialize(PrintJobWorkerOwner* job,
68 PrintedPagesSource* source, 68 PrintedPagesSource* source,
69 int page_count) { 69 int page_count) {
70 DCHECK(!source_); 70 DCHECK(!source_);
71 DCHECK(!worker_.get()); 71 DCHECK(!worker_);
72 DCHECK(!is_job_pending_); 72 DCHECK(!is_job_pending_);
73 DCHECK(!is_canceling_); 73 DCHECK(!is_canceling_);
74 DCHECK(!document_.get()); 74 DCHECK(!document_.get());
75 source_ = source; 75 source_ = source;
76 worker_.reset(job->DetachWorker(this)); 76 worker_.reset(job->DetachWorker(this));
77 settings_ = job->settings(); 77 settings_ = job->settings();
78 78
79 PrintedDocument* new_doc = 79 PrintedDocument* new_doc =
80 new PrintedDocument(settings_, 80 new PrintedDocument(settings_,
81 source_, 81 source_,
(...skipping 16 matching lines...) Expand all
98 OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr()); 98 OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
99 } 99 }
100 100
101 void PrintJob::GetSettingsDone(const PrintSettings& new_settings, 101 void PrintJob::GetSettingsDone(const PrintSettings& new_settings,
102 PrintingContext::Result result) { 102 PrintingContext::Result result) {
103 NOTREACHED(); 103 NOTREACHED();
104 } 104 }
105 105
106 PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) { 106 PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) {
107 NOTREACHED(); 107 NOTREACHED();
108 return NULL; 108 return nullptr;
109 } 109 }
110 110
111 const PrintSettings& PrintJob::settings() const { 111 const PrintSettings& PrintJob::settings() const {
112 return settings_; 112 return settings_;
113 } 113 }
114 114
115 int PrintJob::cookie() const { 115 int PrintJob::cookie() const {
116 // Always use an invalid cookie in this case.
116 if (!document_.get()) 117 if (!document_.get())
117 // Always use an invalid cookie in this case.
118 return 0; 118 return 0;
119 return document_->cookie(); 119 return document_->cookie();
120 } 120 }
121 121
122 void PrintJob::StartPrinting() { 122 void PrintJob::StartPrinting() {
123 DCHECK(RunsTasksOnCurrentThread()); 123 DCHECK(RunsTasksOnCurrentThread());
124 DCHECK(worker_->IsRunning()); 124 if (!worker_->IsRunning() || is_job_pending_) {
125 DCHECK(!is_job_pending_); 125 NOTREACHED();
126 if (!worker_->IsRunning() || is_job_pending_)
127 return; 126 return;
127 }
128 128
129 // Real work is done in PrintJobWorker::StartPrinting(). 129 // Real work is done in PrintJobWorker::StartPrinting().
130 worker_->PostTask(FROM_HERE, 130 worker_->PostTask(FROM_HERE,
131 base::Bind(&HoldRefCallback, make_scoped_refptr(this), 131 base::Bind(&HoldRefCallback, make_scoped_refptr(this),
132 base::Bind(&PrintJobWorker::StartPrinting, 132 base::Bind(&PrintJobWorker::StartPrinting,
133 base::Unretained(worker_.get()), 133 base::Unretained(worker_.get()),
134 base::RetainedRef(document_)))); 134 base::RetainedRef(document_))));
135 // Set the flag right now. 135 // Set the flag right now.
136 is_job_pending_ = true; 136 is_job_pending_ = true;
137 137
138 // Tell everyone! 138 // Tell everyone!
139 scoped_refptr<JobEventDetails> details( 139 scoped_refptr<JobEventDetails> details(
140 new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), NULL)); 140 new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), nullptr));
141 content::NotificationService::current()->Notify( 141 content::NotificationService::current()->Notify(
142 chrome::NOTIFICATION_PRINT_JOB_EVENT, 142 chrome::NOTIFICATION_PRINT_JOB_EVENT,
143 content::Source<PrintJob>(this), 143 content::Source<PrintJob>(this),
144 content::Details<JobEventDetails>(details.get())); 144 content::Details<JobEventDetails>(details.get()));
145 } 145 }
146 146
147 void PrintJob::Stop() { 147 void PrintJob::Stop() {
148 DCHECK(RunsTasksOnCurrentThread()); 148 DCHECK(RunsTasksOnCurrentThread());
149 149
150 if (quit_factory_.HasWeakPtrs()) { 150 if (quit_factory_.HasWeakPtrs()) {
(...skipping 24 matching lines...) Expand all
175 scoped_refptr<PrintJob> handle(this); 175 scoped_refptr<PrintJob> handle(this);
176 176
177 DCHECK(RunsTasksOnCurrentThread()); 177 DCHECK(RunsTasksOnCurrentThread());
178 if (worker_ && worker_->IsRunning()) { 178 if (worker_ && worker_->IsRunning()) {
179 // Call this right now so it renders the context invalid. Do not use 179 // Call this right now so it renders the context invalid. Do not use
180 // InvokeLater since it would take too much time. 180 // InvokeLater since it would take too much time.
181 worker_->Cancel(); 181 worker_->Cancel();
182 } 182 }
183 // Make sure a Cancel() is broadcast. 183 // Make sure a Cancel() is broadcast.
184 scoped_refptr<JobEventDetails> details( 184 scoped_refptr<JobEventDetails> details(
185 new JobEventDetails(JobEventDetails::FAILED, NULL, NULL)); 185 new JobEventDetails(JobEventDetails::FAILED, nullptr, nullptr));
186 content::NotificationService::current()->Notify( 186 content::NotificationService::current()->Notify(
187 chrome::NOTIFICATION_PRINT_JOB_EVENT, 187 chrome::NOTIFICATION_PRINT_JOB_EVENT,
188 content::Source<PrintJob>(this), 188 content::Source<PrintJob>(this),
189 content::Details<JobEventDetails>(details.get())); 189 content::Details<JobEventDetails>(details.get()));
190 Stop(); 190 Stop();
191 is_canceling_ = false; 191 is_canceling_ = false;
192 } 192 }
193 193
194 bool PrintJob::FlushJob(base::TimeDelta timeout) { 194 bool PrintJob::FlushJob(base::TimeDelta timeout) {
195 // Make sure the object outlive this message loop. 195 // Make sure the object outlive this message loop.
196 scoped_refptr<PrintJob> handle(this); 196 scoped_refptr<PrintJob> handle(this);
197 197
198 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 198 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
199 FROM_HERE, base::Bind(&PrintJob::Quit, quit_factory_.GetWeakPtr()), 199 FROM_HERE, base::Bind(&PrintJob::Quit, quit_factory_.GetWeakPtr()),
200 timeout); 200 timeout);
201 201
202 base::MessageLoop::ScopedNestableTaskAllower allow( 202 base::MessageLoop::ScopedNestableTaskAllower allow(
203 base::MessageLoop::current()); 203 base::MessageLoop::current());
204 base::RunLoop().Run(); 204 base::RunLoop().Run();
205 205
206 return true; 206 return true;
207 } 207 }
208 208
209 void PrintJob::DisconnectSource() { 209 void PrintJob::DisconnectSource() {
210 source_ = NULL; 210 source_ = nullptr;
211 if (document_.get()) 211 if (document_.get())
212 document_->DisconnectSource(); 212 document_->DisconnectSource();
213 } 213 }
214 214
215 bool PrintJob::is_job_pending() const { 215 bool PrintJob::is_job_pending() const {
216 return is_job_pending_; 216 return is_job_pending_;
217 } 217 }
218 218
219 PrintedDocument* PrintJob::document() const { 219 PrintedDocument* PrintJob::document() const {
220 return document_.get(); 220 return document_.get();
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 263
264 private: 264 private:
265 int page_count_; 265 int page_count_;
266 int current_page_; 266 int current_page_;
267 int pages_in_progress_; 267 int pages_in_progress_;
268 gfx::Size page_size_; 268 gfx::Size page_size_;
269 gfx::Rect content_area_; 269 gfx::Rect content_area_;
270 std::unique_ptr<PdfToEmfConverter> converter_; 270 std::unique_ptr<PdfToEmfConverter> converter_;
271 }; 271 };
272 272
273 void PrintJob::AppendPrintedPage(int page_number) {
274 pdf_page_mapping_.push_back(page_number);
275 }
276
273 void PrintJob::StartPdfToEmfConversion( 277 void PrintJob::StartPdfToEmfConversion(
274 const scoped_refptr<base::RefCountedMemory>& bytes, 278 const scoped_refptr<base::RefCountedMemory>& bytes,
275 const gfx::Size& page_size, 279 const gfx::Size& page_size,
276 const gfx::Rect& content_area) { 280 const gfx::Rect& content_area) {
277 DCHECK(!ptd_to_emf_state_.get()); 281 DCHECK(!pdf_to_emf_state_);
278 ptd_to_emf_state_.reset(new PdfToEmfState(page_size, content_area)); 282 pdf_to_emf_state_ = base::MakeUnique<PdfToEmfState>(page_size, content_area);
279 const int kPrinterDpi = settings().dpi(); 283 const int kPrinterDpi = settings().dpi();
280 ptd_to_emf_state_->Start( 284 pdf_to_emf_state_->Start(bytes,
281 bytes, 285 PdfRenderSettings(content_area, kPrinterDpi, true),
282 printing::PdfRenderSettings(content_area, kPrinterDpi, true), 286 base::Bind(&PrintJob::OnPdfToEmfStarted, this));
283 base::Bind(&PrintJob::OnPdfToEmfStarted, this));
284 } 287 }
285 288
286 void PrintJob::OnPdfToEmfStarted(int page_count) { 289 void PrintJob::OnPdfToEmfStarted(int page_count) {
287 if (page_count <= 0) { 290 if (page_count <= 0) {
288 ptd_to_emf_state_.reset(); 291 pdf_to_emf_state_.reset();
289 Cancel(); 292 Cancel();
290 return; 293 return;
291 } 294 }
292 ptd_to_emf_state_->set_page_count(page_count); 295 pdf_to_emf_state_->set_page_count(page_count);
293 ptd_to_emf_state_->GetMorePages( 296 pdf_to_emf_state_->GetMorePages(
294 base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); 297 base::Bind(&PrintJob::OnPdfToEmfPageConverted, this));
295 } 298 }
296 299
297 void PrintJob::OnPdfToEmfPageConverted(int page_number, 300 void PrintJob::OnPdfToEmfPageConverted(int page_number,
298 float scale_factor, 301 float scale_factor,
299 std::unique_ptr<MetafilePlayer> emf) { 302 std::unique_ptr<MetafilePlayer> emf) {
300 DCHECK(ptd_to_emf_state_); 303 DCHECK(pdf_to_emf_state_);
301 if (!document_.get() || !emf) { 304 if (!document_.get() || !emf || page_number < 0 ||
302 ptd_to_emf_state_.reset(); 305 static_cast<size_t>(page_number) >= pdf_page_mapping_.size()) {
306 pdf_to_emf_state_.reset();
303 Cancel(); 307 Cancel();
304 return; 308 return;
305 } 309 }
306 310
307 // Update the rendered document. It will send notifications to the listener. 311 // Update the rendered document. It will send notifications to the listener.
308 document_->SetPage(page_number, std::move(emf), scale_factor, 312 document_->SetPage(pdf_page_mapping_[page_number], std::move(emf),
309 ptd_to_emf_state_->page_size(), 313 scale_factor, pdf_to_emf_state_->page_size(),
310 ptd_to_emf_state_->content_area()); 314 pdf_to_emf_state_->content_area());
311 315
312 ptd_to_emf_state_->GetMorePages( 316 pdf_to_emf_state_->GetMorePages(
313 base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); 317 base::Bind(&PrintJob::OnPdfToEmfPageConverted, this));
314 } 318 }
315 319
316 #endif // OS_WIN 320 #endif // OS_WIN
317 321
318 void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) { 322 void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
319 if (document_.get() == new_document) 323 if (document_.get() == new_document)
320 return; 324 return;
321 325
322 document_ = new_document; 326 document_ = new_document;
323 327
324 if (document_.get()) { 328 if (document_.get())
325 settings_ = document_->settings(); 329 settings_ = document_->settings();
326 }
327 330
328 if (worker_) { 331 if (worker_) {
329 DCHECK(!is_job_pending_); 332 DCHECK(!is_job_pending_);
330 // Sync the document with the worker. 333 // Sync the document with the worker.
331 worker_->PostTask(FROM_HERE, 334 worker_->PostTask(FROM_HERE,
332 base::Bind(&HoldRefCallback, make_scoped_refptr(this), 335 base::Bind(&HoldRefCallback, make_scoped_refptr(this),
333 base::Bind(&PrintJobWorker::OnDocumentChanged, 336 base::Bind(&PrintJobWorker::OnDocumentChanged,
334 base::Unretained(worker_.get()), 337 base::Unretained(worker_.get()),
335 base::RetainedRef(document_)))); 338 base::RetainedRef(document_))));
336 } 339 }
(...skipping 21 matching lines...) Expand all
358 break; 361 break;
359 } 362 }
360 case JobEventDetails::DOC_DONE: { 363 case JobEventDetails::DOC_DONE: {
361 // This will call Stop() and broadcast a JOB_DONE message. 364 // This will call Stop() and broadcast a JOB_DONE message.
362 base::ThreadTaskRunnerHandle::Get()->PostTask( 365 base::ThreadTaskRunnerHandle::Get()->PostTask(
363 FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this)); 366 FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this));
364 break; 367 break;
365 } 368 }
366 case JobEventDetails::PAGE_DONE: 369 case JobEventDetails::PAGE_DONE:
367 #if defined(OS_WIN) 370 #if defined(OS_WIN)
368 ptd_to_emf_state_->OnPageProcessed( 371 pdf_to_emf_state_->OnPageProcessed(
369 base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); 372 base::Bind(&PrintJob::OnPdfToEmfPageConverted, this));
370 #endif // OS_WIN 373 #endif // defined(OS_WIN)
371 break; 374 break;
372 default: { 375 default: {
373 NOTREACHED(); 376 NOTREACHED();
374 break; 377 break;
375 } 378 }
376 } 379 }
377 } 380 }
378 381
379 void PrintJob::OnDocumentDone() { 382 void PrintJob::OnDocumentDone() {
380 // Be sure to live long enough. The instance could be destroyed by the 383 // Be sure to live long enough. The instance could be destroyed by the
381 // JOB_DONE broadcast. 384 // JOB_DONE broadcast.
382 scoped_refptr<PrintJob> handle(this); 385 scoped_refptr<PrintJob> handle(this);
383 386
384 // Stop the worker thread. 387 // Stop the worker thread.
385 Stop(); 388 Stop();
386 389
387 scoped_refptr<JobEventDetails> details( 390 scoped_refptr<JobEventDetails> details(
388 new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), NULL)); 391 new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), nullptr));
389 content::NotificationService::current()->Notify( 392 content::NotificationService::current()->Notify(
390 chrome::NOTIFICATION_PRINT_JOB_EVENT, 393 chrome::NOTIFICATION_PRINT_JOB_EVENT,
391 content::Source<PrintJob>(this), 394 content::Source<PrintJob>(this),
392 content::Details<JobEventDetails>(details.get())); 395 content::Details<JobEventDetails>(details.get()));
393 } 396 }
394 397
395 void PrintJob::ControlledWorkerShutdown() { 398 void PrintJob::ControlledWorkerShutdown() {
396 DCHECK(RunsTasksOnCurrentThread()); 399 DCHECK(RunsTasksOnCurrentThread());
397 400
398 // The deadlock this code works around is specific to window messaging on 401 // The deadlock this code works around is specific to window messaging on
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 } 453 }
451 454
452 JobEventDetails::~JobEventDetails() { 455 JobEventDetails::~JobEventDetails() {
453 } 456 }
454 457
455 PrintedDocument* JobEventDetails::document() const { return document_.get(); } 458 PrintedDocument* JobEventDetails::document() const { return document_.get(); }
456 459
457 PrintedPage* JobEventDetails::page() const { return page_.get(); } 460 PrintedPage* JobEventDetails::page() const { return page_.get(); }
458 461
459 } // namespace printing 462 } // namespace printing
OLDNEW
« no previous file with comments | « chrome/browser/printing/print_job.h ('k') | chrome/browser/printing/print_view_manager_base.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698