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 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_EQ(io_message_loop_->type(), base::MessageLoop::TYPE_IO); 24 } 25 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 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 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 60 base::MessageLoop* PrinterQuery::message_loop() { 61 return io_message_loop_; 62 } 63 64 const PrintSettings& PrinterQuery::settings() const { 65 return settings_; 66 } 67 68 int PrinterQuery::cookie() const { 69 return cookie_; 70 } 71 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 97 void PrinterQuery::SetSettings(const 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 108 void PrinterQuery::SetWorkerDestination( 109 PrintDestinationInterface* destination) { 110 worker_->SetPrintDestination(destination); 111 } 112 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 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 135 bool PrinterQuery::is_callback_pending() const { 136 return !callback_.is_null(); 137 } 138 139 bool PrinterQuery::is_valid() const { 140 return worker_.get() != NULL; 141 } 142 143 } // namespace printing 144