Home | History | Annotate | Download | only in printing
      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