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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/printing/printer_query.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "base/values.h"
12 #include "chrome/browser/printing/print_job_worker.h"
13 #include "chrome/browser/printing/printing_ui_web_contents_observer.h"
14
15 namespace printing {
16
PrinterQuery()17 PrinterQuery::PrinterQuery()
18 : io_message_loop_(base::MessageLoop::current()),
19 worker_(new PrintJobWorker(this)),
20 is_print_dialog_box_shown_(false),
21 cookie_(PrintSettings::NewCookie()),
22 last_status_(PrintingContext::FAILED) {
23 DCHECK(base::MessageLoopForIO::IsCurrent());
24 }
25
~PrinterQuery()26 PrinterQuery::~PrinterQuery() {
27 // The job should be finished (or at least canceled) when it is destroyed.
28 DCHECK(!is_print_dialog_box_shown_);
29 // If this fires, it is that this pending printer context has leaked.
30 DCHECK(!worker_.get());
31 }
32
GetSettingsDone(const PrintSettings & new_settings,PrintingContext::Result result)33 void PrinterQuery::GetSettingsDone(const PrintSettings& new_settings,
34 PrintingContext::Result result) {
35 is_print_dialog_box_shown_ = false;
36 last_status_ = result;
37 if (result != PrintingContext::FAILED) {
38 settings_ = new_settings;
39 cookie_ = PrintSettings::NewCookie();
40 } else {
41 // Failure.
42 cookie_ = 0;
43 }
44
45 if (!callback_.is_null()) {
46 // This may cause reentrancy like to call StopWorker().
47 callback_.Run();
48 callback_.Reset();
49 }
50 }
51
DetachWorker(PrintJobWorkerOwner * new_owner)52 PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) {
53 DCHECK(callback_.is_null());
54 DCHECK(worker_.get());
55
56 worker_->SetNewOwner(new_owner);
57 return worker_.release();
58 }
59
message_loop()60 base::MessageLoop* PrinterQuery::message_loop() {
61 return io_message_loop_;
62 }
63
settings() const64 const PrintSettings& PrinterQuery::settings() const {
65 return settings_;
66 }
67
cookie() const68 int PrinterQuery::cookie() const {
69 return cookie_;
70 }
71
GetSettings(GetSettingsAskParam ask_user_for_settings,scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,int expected_page_count,bool has_selection,MarginType margin_type,const base::Closure & callback)72 void PrinterQuery::GetSettings(
73 GetSettingsAskParam ask_user_for_settings,
74 scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
75 int expected_page_count,
76 bool has_selection,
77 MarginType margin_type,
78 const base::Closure& callback) {
79 DCHECK_EQ(io_message_loop_, base::MessageLoop::current());
80 DCHECK(!is_print_dialog_box_shown_);
81
82 StartWorker(callback);
83
84 // Real work is done in PrintJobWorker::GetSettings().
85 is_print_dialog_box_shown_ = ask_user_for_settings == ASK_USER;
86 worker_->message_loop()->PostTask(
87 FROM_HERE,
88 base::Bind(&PrintJobWorker::GetSettings,
89 base::Unretained(worker_.get()),
90 is_print_dialog_box_shown_,
91 base::Passed(&web_contents_observer),
92 expected_page_count,
93 has_selection,
94 margin_type));
95 }
96
SetSettings(const base::DictionaryValue & new_settings,const base::Closure & callback)97 void PrinterQuery::SetSettings(const base::DictionaryValue& new_settings,
98 const base::Closure& callback) {
99 StartWorker(callback);
100
101 worker_->message_loop()->PostTask(
102 FROM_HERE,
103 base::Bind(&PrintJobWorker::SetSettings,
104 base::Unretained(worker_.get()),
105 new_settings.DeepCopy()));
106 }
107
SetWorkerDestination(PrintDestinationInterface * destination)108 void PrinterQuery::SetWorkerDestination(
109 PrintDestinationInterface* destination) {
110 worker_->SetPrintDestination(destination);
111 }
112
StartWorker(const base::Closure & callback)113 void PrinterQuery::StartWorker(const base::Closure& callback) {
114 DCHECK(callback_.is_null());
115 DCHECK(worker_.get());
116
117 // Lazily create the worker thread. There is one worker thread per print job.
118 if (!worker_->message_loop())
119 worker_->Start();
120
121 callback_ = callback;
122 }
123
StopWorker()124 void PrinterQuery::StopWorker() {
125 if (worker_.get()) {
126 // http://crbug.com/66082: We're blocking on the PrinterQuery's worker
127 // thread. It's not clear to me if this may result in blocking the current
128 // thread for an unacceptable time. We should probably fix it.
129 base::ThreadRestrictions::ScopedAllowIO allow_io;
130 worker_->Stop();
131 worker_.reset();
132 }
133 }
134
is_callback_pending() const135 bool PrinterQuery::is_callback_pending() const {
136 return !callback_.is_null();
137 }
138
is_valid() const139 bool PrinterQuery::is_valid() const {
140 return worker_.get() != NULL;
141 }
142
143 } // namespace printing
144