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 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 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 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 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 62 MessageLoop* PrinterQuery::message_loop() { 63 return io_message_loop_; 64 } 65 66 const PrintSettings& PrinterQuery::settings() const { 67 return settings_; 68 } 69 70 int PrinterQuery::cookie() const { 71 return cookie_; 72 } 73 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 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 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 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 140 bool PrinterQuery::is_callback_pending() const { 141 return callback_.get() != NULL; 142 } 143 144 bool PrinterQuery::is_valid() const { 145 return worker_.get() != NULL; 146 } 147 148 } // namespace printing 149