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