1 // Copyright (c) 2011 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/message_loop.h"
8 #include "base/threading/thread_restrictions.h"
9 #include "base/values.h"
10 #include "chrome/browser/printing/print_job_worker.h"
11
12 namespace printing {
13
PrinterQuery()14 PrinterQuery::PrinterQuery()
15 : io_message_loop_(MessageLoop::current()),
16 ALLOW_THIS_IN_INITIALIZER_LIST(worker_(new PrintJobWorker(this))),
17 is_print_dialog_box_shown_(false),
18 cookie_(PrintSettings::NewCookie()),
19 last_status_(PrintingContext::FAILED) {
20 DCHECK_EQ(io_message_loop_->type(), MessageLoop::TYPE_IO);
21 }
22
~PrinterQuery()23 PrinterQuery::~PrinterQuery() {
24 // The job should be finished (or at least canceled) when it is destroyed.
25 DCHECK(!is_print_dialog_box_shown_);
26 // If this fires, it is that this pending printer context has leaked.
27 DCHECK(!worker_.get());
28 if (callback_.get()) {
29 // Be sure to cancel it.
30 callback_->Cancel();
31 }
32 // It may get deleted in a different thread that the one that created it.
33 }
34
GetSettingsDone(const PrintSettings & new_settings,PrintingContext::Result result)35 void PrinterQuery::GetSettingsDone(const PrintSettings& new_settings,
36 PrintingContext::Result result) {
37 is_print_dialog_box_shown_ = false;
38 last_status_ = result;
39 if (result != PrintingContext::FAILED) {
40 settings_ = new_settings;
41 cookie_ = PrintSettings::NewCookie();
42 } else {
43 // Failure.
44 cookie_ = 0;
45 }
46 if (callback_.get()) {
47 // This may cause reentrancy like to call StopWorker().
48 callback_->Run();
49 callback_.reset(NULL);
50 }
51 }
52
DetachWorker(PrintJobWorkerOwner * new_owner)53 PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) {
54 DCHECK(!callback_.get());
55 DCHECK(worker_.get());
56 if (!worker_.get())
57 return NULL;
58 worker_->SetNewOwner(new_owner);
59 return worker_.release();
60 }
61
message_loop()62 MessageLoop* PrinterQuery::message_loop() {
63 return io_message_loop_;
64 }
65
settings() const66 const PrintSettings& PrinterQuery::settings() const {
67 return settings_;
68 }
69
cookie() const70 int PrinterQuery::cookie() const {
71 return cookie_;
72 }
73
GetSettings(GetSettingsAskParam ask_user_for_settings,gfx::NativeView parent_view,int expected_page_count,bool has_selection,bool use_overlays,CancelableTask * callback)74 void PrinterQuery::GetSettings(GetSettingsAskParam ask_user_for_settings,
75 gfx::NativeView parent_view,
76 int expected_page_count,
77 bool has_selection,
78 bool use_overlays,
79 CancelableTask* callback) {
80 DCHECK_EQ(io_message_loop_, MessageLoop::current());
81 DCHECK(!is_print_dialog_box_shown_);
82 if (!StartWorker(callback))
83 return;
84
85 // Real work is done in PrintJobWorker::Init().
86 is_print_dialog_box_shown_ = ask_user_for_settings == ASK_USER;
87 worker_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
88 worker_.get(),
89 &PrintJobWorker::GetSettings,
90 is_print_dialog_box_shown_,
91 parent_view,
92 expected_page_count,
93 has_selection,
94 use_overlays));
95 }
96
SetSettings(const DictionaryValue & new_settings,CancelableTask * callback)97 void PrinterQuery::SetSettings(const DictionaryValue& new_settings,
98 CancelableTask* callback) {
99 if (!StartWorker(callback))
100 return;
101
102 worker_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
103 worker_.get(),
104 &PrintJobWorker::SetSettings,
105 new_settings.DeepCopy()));
106 }
107
StartWorker(CancelableTask * callback)108 bool PrinterQuery::StartWorker(CancelableTask* callback) {
109 DCHECK(!callback_.get());
110 DCHECK(worker_.get());
111 if (!worker_.get())
112 return false;
113
114 // Lazy create the worker thread. There is one worker thread per print job.
115 if (!worker_->message_loop()) {
116 if (!worker_->Start()) {
117 if (callback) {
118 callback->Cancel();
119 delete callback;
120 }
121 NOTREACHED();
122 return false;
123 }
124 }
125 callback_.reset(callback);
126 return true;
127 }
128
StopWorker()129 void PrinterQuery::StopWorker() {
130 if (worker_.get()) {
131 // http://crbug.com/66082: We're blocking on the PrinterQuery's worker
132 // thread. It's not clear to me if this may result in blocking the current
133 // thread for an unacceptable time. We should probably fix it.
134 base::ThreadRestrictions::ScopedAllowIO allow_io;
135 worker_->Stop();
136 worker_.reset();
137 }
138 }
139
is_callback_pending() const140 bool PrinterQuery::is_callback_pending() const {
141 return callback_.get() != NULL;
142 }
143
is_valid() const144 bool PrinterQuery::is_valid() const {
145 return worker_.get() != NULL;
146 }
147
148 } // namespace printing
149