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 #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