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