Home | History | Annotate | Download | only in print_preview
      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/ui/webui/print_preview/print_preview_handler.h"
      6 
      7 #include <ctype.h>
      8 
      9 #include <string>
     10 
     11 #include "base/base64.h"
     12 #include "base/bind.h"
     13 #include "base/bind_helpers.h"
     14 #include "base/command_line.h"
     15 #include "base/i18n/file_util_icu.h"
     16 #include "base/i18n/number_formatting.h"
     17 #include "base/json/json_reader.h"
     18 #include "base/lazy_instance.h"
     19 #include "base/memory/linked_ptr.h"
     20 #include "base/memory/ref_counted_memory.h"
     21 #include "base/metrics/histogram.h"
     22 #include "base/path_service.h"
     23 #include "base/prefs/pref_service.h"
     24 #include "base/strings/utf_string_conversions.h"
     25 #include "base/threading/thread.h"
     26 #include "base/threading/thread_restrictions.h"
     27 #include "base/values.h"
     28 #include "chrome/browser/browser_process.h"
     29 #include "chrome/browser/platform_util.h"
     30 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
     31 #include "chrome/browser/printing/print_dialog_cloud.h"
     32 #include "chrome/browser/printing/print_error_dialog.h"
     33 #include "chrome/browser/printing/print_job_manager.h"
     34 #include "chrome/browser/printing/print_preview_dialog_controller.h"
     35 #include "chrome/browser/printing/print_view_manager.h"
     36 #include "chrome/browser/printing/printer_manager_dialog.h"
     37 #include "chrome/browser/profiles/profile.h"
     38 #include "chrome/browser/signin/profile_oauth2_token_service.h"
     39 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     40 #include "chrome/browser/signin/signin_manager.h"
     41 #include "chrome/browser/signin/signin_manager_base.h"
     42 #include "chrome/browser/signin/signin_manager_factory.h"
     43 #include "chrome/browser/ui/browser_finder.h"
     44 #include "chrome/browser/ui/browser_tabstrip.h"
     45 #include "chrome/browser/ui/chrome_select_file_policy.h"
     46 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
     47 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
     48 #include "chrome/common/chrome_paths.h"
     49 #include "chrome/common/chrome_switches.h"
     50 #include "chrome/common/cloud_print/cloud_print_constants.h"
     51 #include "chrome/common/crash_keys.h"
     52 #include "chrome/common/pref_names.h"
     53 #include "chrome/common/print_messages.h"
     54 #include "content/public/browser/browser_context.h"
     55 #include "content/public/browser/browser_thread.h"
     56 #include "content/public/browser/navigation_controller.h"
     57 #include "content/public/browser/navigation_entry.h"
     58 #include "content/public/browser/render_view_host.h"
     59 #include "content/public/browser/web_contents.h"
     60 #include "content/public/browser/web_contents_view.h"
     61 #include "content/public/browser/web_ui.h"
     62 #include "google_apis/gaia/oauth2_token_service.h"
     63 #include "printing/backend/print_backend.h"
     64 #include "printing/metafile.h"
     65 #include "printing/metafile_impl.h"
     66 #include "printing/pdf_render_settings.h"
     67 #include "printing/print_settings.h"
     68 #include "printing/units.h"
     69 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
     70 
     71 #if defined(OS_CHROMEOS)
     72 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
     73 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
     74 #endif
     75 
     76 #if defined(ENABLE_MDNS)
     77 #include "chrome/browser/local_discovery/privet_constants.h"
     78 #endif
     79 
     80 using content::BrowserThread;
     81 using content::RenderViewHost;
     82 using content::WebContents;
     83 
     84 namespace {
     85 
     86 enum UserActionBuckets {
     87   PRINT_TO_PRINTER,
     88   PRINT_TO_PDF,
     89   CANCEL,
     90   FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
     91   PREVIEW_FAILED,
     92   PREVIEW_STARTED,
     93   INITIATOR_CRASHED,  // UNUSED
     94   INITIATOR_CLOSED,
     95   PRINT_WITH_CLOUD_PRINT,
     96   PRINT_WITH_PRIVET,
     97   USERACTION_BUCKET_BOUNDARY
     98 };
     99 
    100 enum PrintSettingsBuckets {
    101   LANDSCAPE = 0,
    102   PORTRAIT,
    103   COLOR,
    104   BLACK_AND_WHITE,
    105   COLLATE,
    106   SIMPLEX,
    107   DUPLEX,
    108   TOTAL,
    109   HEADERS_AND_FOOTERS,
    110   CSS_BACKGROUND,
    111   SELECTION_ONLY,
    112   PRINT_SETTINGS_BUCKET_BOUNDARY
    113 };
    114 
    115 enum UiBucketGroups {
    116   DESTINATION_SEARCH,
    117   GCP_PROMO,
    118   UI_BUCKET_GROUP_BOUNDARY
    119 };
    120 
    121 enum PrintDestinationBuckets {
    122   DESTINATION_SHOWN,
    123   DESTINATION_CLOSED_CHANGED,
    124   DESTINATION_CLOSED_UNCHANGED,
    125   SIGNIN_PROMPT,
    126   SIGNIN_TRIGGERED,
    127   PRIVET_DUPLICATE_SELECTED,
    128   CLOUD_DUPLICATE_SELECTED,
    129   PRINT_DESTINATION_BUCKET_BOUNDARY
    130 };
    131 
    132 enum GcpPromoBuckets {
    133   PROMO_SHOWN,
    134   PROMO_CLOSED,
    135   PROMO_CLICKED,
    136   GCP_PROMO_BUCKET_BOUNDARY
    137 };
    138 
    139 void ReportUserActionHistogram(enum UserActionBuckets event) {
    140   UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
    141                             USERACTION_BUCKET_BOUNDARY);
    142 }
    143 
    144 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
    145   UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
    146                             PRINT_SETTINGS_BUCKET_BOUNDARY);
    147 }
    148 
    149 void ReportPrintDestinationHistogram(enum PrintDestinationBuckets event) {
    150   UMA_HISTOGRAM_ENUMERATION("PrintPreview.DestinationAction", event,
    151                             PRINT_DESTINATION_BUCKET_BOUNDARY);
    152 }
    153 
    154 void ReportGcpPromoHistogram(enum GcpPromoBuckets event) {
    155   UMA_HISTOGRAM_ENUMERATION("PrintPreview.GcpPromo", event,
    156                             GCP_PROMO_BUCKET_BOUNDARY);
    157 }
    158 
    159 // Name of a dictionary field holding cloud print related data;
    160 const char kAppState[] = "appState";
    161 // Name of a dictionary field holding the initiator title.
    162 const char kInitiatorTitle[] = "initiatorTitle";
    163 // Name of a dictionary field holding the measurement system according to the
    164 // locale.
    165 const char kMeasurementSystem[] = "measurementSystem";
    166 // Name of a dictionary field holding the number format according to the locale.
    167 const char kNumberFormat[] = "numberFormat";
    168 // Name of a dictionary field specifying whether to print automatically in
    169 // kiosk mode. See http://crbug.com/31395.
    170 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
    171 #if defined(OS_WIN)
    172 const char kHidePrintWithSystemDialogLink[] = "hidePrintWithSystemDialogLink";
    173 #endif
    174 // Name of a dictionary field holding the state of selection for document.
    175 const char kDocumentHasSelection[] = "documentHasSelection";
    176 
    177 // Additional printer capability setting keys.
    178 const char kPrinterId[] = "printerId";
    179 const char kDisableColorOption[] = "disableColorOption";
    180 const char kSetDuplexAsDefault[] = "setDuplexAsDefault";
    181 const char kPrinterDefaultDuplexValue[] = "printerDefaultDuplexValue";
    182 #if defined(USE_CUPS)
    183 const char kCUPSsColorModel[] = "cupsColorModel";
    184 const char kCUPSsBWModel[] = "cupsBWModel";
    185 #endif
    186 
    187 #if defined(ENABLE_MDNS)
    188 const int kPrivetPrinterSearchDurationSeconds = 3;
    189 #endif
    190 
    191 // Get the print job settings dictionary from |args|. The caller takes
    192 // ownership of the returned DictionaryValue. Returns NULL on failure.
    193 DictionaryValue* GetSettingsDictionary(const ListValue* args) {
    194   std::string json_str;
    195   if (!args->GetString(0, &json_str)) {
    196     NOTREACHED() << "Could not read JSON argument";
    197     return NULL;
    198   }
    199   if (json_str.empty()) {
    200     NOTREACHED() << "Empty print job settings";
    201     return NULL;
    202   }
    203   scoped_ptr<DictionaryValue> settings(static_cast<DictionaryValue*>(
    204       base::JSONReader::Read(json_str)));
    205   if (!settings.get() || !settings->IsType(Value::TYPE_DICTIONARY)) {
    206     NOTREACHED() << "Print job settings must be a dictionary.";
    207     return NULL;
    208   }
    209 
    210   if (settings->empty()) {
    211     NOTREACHED() << "Print job settings dictionary is empty";
    212     return NULL;
    213   }
    214 
    215   return settings.release();
    216 }
    217 
    218 // Track the popularity of print settings and report the stats.
    219 void ReportPrintSettingsStats(const DictionaryValue& settings) {
    220   ReportPrintSettingHistogram(TOTAL);
    221 
    222   bool landscape = false;
    223   if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
    224     ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
    225 
    226   bool collate = false;
    227   if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
    228     ReportPrintSettingHistogram(COLLATE);
    229 
    230   int duplex_mode = 0;
    231   if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
    232     ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
    233 
    234   int color_mode = 0;
    235   if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
    236     ReportPrintSettingHistogram(
    237         printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
    238   }
    239 
    240   bool headers = false;
    241   if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) &&
    242       headers) {
    243     ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
    244   }
    245 
    246   bool css_background = false;
    247   if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
    248                           &css_background) && css_background) {
    249     ReportPrintSettingHistogram(CSS_BACKGROUND);
    250   }
    251 
    252   bool selection_only = false;
    253   if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
    254                           &selection_only) && selection_only) {
    255     ReportPrintSettingHistogram(SELECTION_ONLY);
    256   }
    257 }
    258 
    259 // Callback that stores a PDF file on disk.
    260 void PrintToPdfCallback(printing::Metafile* metafile,
    261                         const base::FilePath& path) {
    262   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    263   metafile->SaveTo(path);
    264   // |metafile| must be deleted on the UI thread.
    265   BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, metafile);
    266 }
    267 
    268 std::string GetDefaultPrinterOnFileThread(
    269     scoped_refptr<printing::PrintBackend> print_backend) {
    270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    271 
    272   std::string default_printer = print_backend->GetDefaultPrinterName();
    273   VLOG(1) << "Default Printer: " << default_printer;
    274   return default_printer;
    275 }
    276 
    277 void EnumeratePrintersOnFileThread(
    278     scoped_refptr<printing::PrintBackend> print_backend,
    279     base::ListValue* printers) {
    280   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    281 
    282   VLOG(1) << "Enumerate printers start";
    283   printing::PrinterList printer_list;
    284   print_backend->EnumeratePrinters(&printer_list);
    285 
    286   for (printing::PrinterList::iterator it = printer_list.begin();
    287        it != printer_list.end(); ++it) {
    288     base::DictionaryValue* printer_info = new base::DictionaryValue;
    289     std::string printer_name;
    290 #if defined(OS_MACOSX)
    291     // On Mac, |it->printer_description| specifies the printer name and
    292     // |it->printer_name| specifies the device name / printer queue name.
    293     printer_name = it->printer_description;
    294 #else
    295     printer_name = it->printer_name;
    296 #endif
    297     printer_info->SetString(printing::kSettingPrinterName, printer_name);
    298     printer_info->SetString(printing::kSettingDeviceName, it->printer_name);
    299     VLOG(1) << "Found printer " << printer_name
    300             << " with device name " << it->printer_name;
    301     printers->Append(printer_info);
    302   }
    303   VLOG(1) << "Enumerate printers finished, found " << printers->GetSize()
    304           << " printers";
    305 }
    306 
    307 typedef base::Callback<void(const base::DictionaryValue*)>
    308     GetPrinterCapabilitiesSuccessCallback;
    309 typedef base::Callback<void(const std::string&)>
    310     GetPrinterCapabilitiesFailureCallback;
    311 
    312 void GetPrinterCapabilitiesOnFileThread(
    313     scoped_refptr<printing::PrintBackend> print_backend,
    314     const std::string& printer_name,
    315     const GetPrinterCapabilitiesSuccessCallback& success_cb,
    316     const GetPrinterCapabilitiesFailureCallback& failure_cb) {
    317   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    318   DCHECK(!printer_name.empty());
    319 
    320   VLOG(1) << "Get printer capabilities start for " << printer_name;
    321   crash_keys::ScopedPrinterInfo crash_key(
    322       print_backend->GetPrinterDriverInfo(printer_name));
    323 
    324   if (!print_backend->IsValidPrinter(printer_name)) {
    325     // TODO(gene): Notify explicitly if printer is not valid, instead of
    326     // failed to get capabilities.
    327     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    328                             base::Bind(failure_cb, printer_name));
    329     return;
    330   }
    331 
    332   printing::PrinterSemanticCapsAndDefaults info;
    333   if (!print_backend->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
    334     LOG(WARNING) << "Failed to get capabilities for " << printer_name;
    335     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    336                             base::Bind(failure_cb, printer_name));
    337     return;
    338   }
    339 
    340   scoped_ptr<base::DictionaryValue> settings_info(new base::DictionaryValue);
    341   settings_info->SetString(kPrinterId, printer_name);
    342   settings_info->SetBoolean(kDisableColorOption, !info.color_changeable);
    343   settings_info->SetBoolean(printing::kSettingSetColorAsDefault,
    344                             info.color_default);
    345 #if defined(USE_CUPS)
    346   settings_info->SetInteger(kCUPSsColorModel, info.color_model);
    347   settings_info->SetInteger(kCUPSsBWModel, info.bw_model);
    348 #endif
    349 
    350   // TODO(gene): Make new capabilities format for Print Preview
    351   // that will suit semantic capabiltities better.
    352   // Refactor pld API code below
    353   bool default_duplex = info.duplex_capable ?
    354       (info.duplex_default != printing::SIMPLEX) : false;
    355   int duplex_value = info.duplex_capable ?
    356       printing::LONG_EDGE : printing::UNKNOWN_DUPLEX_MODE;
    357   settings_info->SetBoolean(kSetDuplexAsDefault, default_duplex);
    358   settings_info->SetInteger(kPrinterDefaultDuplexValue, duplex_value);
    359 
    360   BrowserThread::PostTask(
    361       BrowserThread::UI, FROM_HERE,
    362       base::Bind(success_cb, base::Owned(settings_info.release())));
    363 }
    364 
    365 base::LazyInstance<printing::StickySettings> g_sticky_settings =
    366     LAZY_INSTANCE_INITIALIZER;
    367 
    368 printing::StickySettings* GetStickySettings() {
    369   return g_sticky_settings.Pointer();
    370 }
    371 
    372 }  // namespace
    373 
    374 #if defined(USE_CUPS)
    375 struct PrintPreviewHandler::CUPSPrinterColorModels {
    376   std::string printer_name;
    377   printing::ColorModel color_model;
    378   printing::ColorModel bw_model;
    379 };
    380 #endif
    381 
    382 class PrintPreviewHandler::AccessTokenService
    383     : public OAuth2TokenService::Consumer {
    384  public:
    385   explicit AccessTokenService(PrintPreviewHandler* handler)
    386       : handler_(handler),
    387         weak_factory_(this) {
    388   }
    389 
    390   void RequestToken(const std::string& type) {
    391     if (requests_.find(type) != requests_.end())
    392       return;  // Already in progress.
    393 
    394     OAuth2TokenService* service = NULL;
    395     std::string account_id;
    396     if (type == "profile") {
    397       Profile* profile = Profile::FromWebUI(handler_->web_ui());
    398       if (profile) {
    399         ProfileOAuth2TokenService* token_service =
    400             ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
    401         account_id = token_service->GetPrimaryAccountId();
    402         service = token_service;
    403       }
    404     } else if (type == "device") {
    405 #if defined(OS_CHROMEOS)
    406       chromeos::DeviceOAuth2TokenServiceFactory::Get(
    407           base::Bind(
    408               &AccessTokenService::DidGetTokenService,
    409               weak_factory_.GetWeakPtr(),
    410               type));
    411       return;
    412 #endif
    413     }
    414 
    415     ContinueRequestToken(type, service, account_id);
    416   }
    417 
    418 #if defined(OS_CHROMEOS)
    419   // Continuation of RequestToken().
    420   void DidGetTokenService(const std::string& type,
    421                           chromeos::DeviceOAuth2TokenService* token_service) {
    422     std::string account_id;
    423     if (token_service)
    424       account_id = token_service->GetRobotAccountId();
    425     ContinueRequestToken(type,
    426                          token_service,
    427                          account_id);
    428   }
    429 #endif
    430 
    431   // Continuation of RequestToken().
    432   void ContinueRequestToken(const std::string& type,
    433                             OAuth2TokenService* service,
    434                             const std::string& account_id) {
    435     if (service) {
    436       OAuth2TokenService::ScopeSet oauth_scopes;
    437       oauth_scopes.insert(cloud_print::kCloudPrintAuth);
    438       scoped_ptr<OAuth2TokenService::Request> request(
    439           service->StartRequest(account_id, oauth_scopes, this));
    440       requests_[type].reset(request.release());
    441     } else {
    442       handler_->SendAccessToken(type, std::string());  // Unknown type.
    443     }
    444   }
    445 
    446   virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
    447                                  const std::string& access_token,
    448                                  const base::Time& expiration_time) OVERRIDE {
    449     OnServiceResponce(request, access_token);
    450   }
    451 
    452   virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
    453                                  const GoogleServiceAuthError& error) OVERRIDE {
    454     OnServiceResponce(request, std::string());
    455   }
    456 
    457  private:
    458   void OnServiceResponce(const OAuth2TokenService::Request* request,
    459                          const std::string& access_token) {
    460     for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
    461       if (i->second == request) {
    462         handler_->SendAccessToken(i->first, access_token);
    463         requests_.erase(i);
    464         return;
    465       }
    466     }
    467     NOTREACHED();
    468   }
    469 
    470   typedef std::map<std::string,
    471                    linked_ptr<OAuth2TokenService::Request> > Requests;
    472   Requests requests_;
    473   PrintPreviewHandler* handler_;
    474   base::WeakPtrFactory<AccessTokenService> weak_factory_;
    475 
    476   DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
    477 };
    478 
    479 PrintPreviewHandler::PrintPreviewHandler()
    480     : print_backend_(printing::PrintBackend::CreateInstance(NULL)),
    481       regenerate_preview_request_count_(0),
    482       manage_printers_dialog_request_count_(0),
    483       manage_cloud_printers_dialog_request_count_(0),
    484       reported_failed_preview_(false),
    485       has_logged_printers_count_(false),
    486       weak_factory_(this) {
    487   ReportUserActionHistogram(PREVIEW_STARTED);
    488 }
    489 
    490 PrintPreviewHandler::~PrintPreviewHandler() {
    491   if (select_file_dialog_.get())
    492     select_file_dialog_->ListenerDestroyed();
    493 }
    494 
    495 void PrintPreviewHandler::RegisterMessages() {
    496   web_ui()->RegisterMessageCallback("getPrinters",
    497       base::Bind(&PrintPreviewHandler::HandleGetPrinters,
    498                  base::Unretained(this)));
    499   web_ui()->RegisterMessageCallback("getPreview",
    500       base::Bind(&PrintPreviewHandler::HandleGetPreview,
    501                  base::Unretained(this)));
    502   web_ui()->RegisterMessageCallback("print",
    503       base::Bind(&PrintPreviewHandler::HandlePrint,
    504                  base::Unretained(this)));
    505   web_ui()->RegisterMessageCallback("getPrinterCapabilities",
    506       base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
    507                  base::Unretained(this)));
    508   web_ui()->RegisterMessageCallback("showSystemDialog",
    509       base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
    510                  base::Unretained(this)));
    511   web_ui()->RegisterMessageCallback("signIn",
    512       base::Bind(&PrintPreviewHandler::HandleSignin,
    513                  base::Unretained(this)));
    514   web_ui()->RegisterMessageCallback("getAccessToken",
    515       base::Bind(&PrintPreviewHandler::HandleGetAccessToken,
    516                  base::Unretained(this)));
    517   web_ui()->RegisterMessageCallback("manageCloudPrinters",
    518       base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
    519                  base::Unretained(this)));
    520   web_ui()->RegisterMessageCallback("manageLocalPrinters",
    521       base::Bind(&PrintPreviewHandler::HandleManagePrinters,
    522                  base::Unretained(this)));
    523   web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
    524       base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog,
    525                  base::Unretained(this)));
    526   web_ui()->RegisterMessageCallback("hidePreview",
    527       base::Bind(&PrintPreviewHandler::HandleHidePreview,
    528                  base::Unretained(this)));
    529   web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
    530       base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
    531                  base::Unretained(this)));
    532   web_ui()->RegisterMessageCallback("saveAppState",
    533       base::Bind(&PrintPreviewHandler::HandleSaveAppState,
    534                  base::Unretained(this)));
    535   web_ui()->RegisterMessageCallback("getInitialSettings",
    536       base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
    537                  base::Unretained(this)));
    538   web_ui()->RegisterMessageCallback("reportUiEvent",
    539       base::Bind(&PrintPreviewHandler::HandleReportUiEvent,
    540                  base::Unretained(this)));
    541   web_ui()->RegisterMessageCallback("printWithCloudPrintDialog",
    542       base::Bind(&PrintPreviewHandler::HandlePrintWithCloudPrintDialog,
    543                  base::Unretained(this)));
    544   web_ui()->RegisterMessageCallback("forceOpenNewTab",
    545       base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
    546                  base::Unretained(this)));
    547   web_ui()->RegisterMessageCallback("getPrivetPrinters",
    548       base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
    549                  base::Unretained(this)));
    550   web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
    551       base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
    552                  base::Unretained(this)));
    553 }
    554 
    555 bool PrintPreviewHandler::PrivetPrintingEnabled() {
    556 #if defined(ENABLE_MDNS)
    557   CommandLine* command_line = CommandLine::ForCurrentProcess();
    558   return !command_line->HasSwitch(switches::kDisableDeviceDiscovery) &&
    559       !command_line->HasSwitch(switches::kDisablePrivetLocalPrinting);
    560 #else
    561   return false;
    562 #endif
    563 }
    564 
    565 WebContents* PrintPreviewHandler::preview_web_contents() const {
    566   return web_ui()->GetWebContents();
    567 }
    568 
    569 void PrintPreviewHandler::HandleGetPrinters(const ListValue* /*args*/) {
    570   base::ListValue* results = new base::ListValue;
    571   BrowserThread::PostTaskAndReply(
    572       BrowserThread::FILE, FROM_HERE,
    573       base::Bind(&EnumeratePrintersOnFileThread, print_backend_,
    574                  base::Unretained(results)),
    575       base::Bind(&PrintPreviewHandler::SetupPrinterList,
    576                  weak_factory_.GetWeakPtr(),
    577                  base::Owned(results)));
    578 }
    579 
    580 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
    581 #if defined(ENABLE_MDNS)
    582   if (PrivetPrintingEnabled()) {
    583     Profile* profile = Profile::FromWebUI(web_ui());
    584     service_discovery_client_ =
    585         local_discovery::ServiceDiscoverySharedClient::GetInstance();
    586     printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
    587         service_discovery_client_.get(),
    588         profile->GetRequestContext(),
    589         this));
    590     printer_lister_->Start();
    591 
    592     base::MessageLoop::current()->PostDelayedTask(
    593         FROM_HERE,
    594         base::Bind(&PrintPreviewHandler::StopPrivetPrinterSearch,
    595                    weak_factory_.GetWeakPtr()),
    596         base::TimeDelta::FromSeconds(kPrivetPrinterSearchDurationSeconds));
    597   }
    598 #endif
    599 
    600   if (!PrivetPrintingEnabled()) {
    601     web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
    602   }
    603 }
    604 
    605 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
    606     const base::ListValue* args) {
    607 #if defined(ENABLE_MDNS)
    608   std::string name;
    609   bool success = args->GetString(0, &name);
    610   DCHECK(success);
    611 
    612   CreatePrivetHTTP(
    613       name,
    614       base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
    615                  base::Unretained(this)));
    616 #endif
    617 }
    618 
    619 void PrintPreviewHandler::HandleGetPreview(const ListValue* args) {
    620   DCHECK_EQ(3U, args->GetSize());
    621   scoped_ptr<DictionaryValue> settings(GetSettingsDictionary(args));
    622   if (!settings.get())
    623     return;
    624   int request_id = -1;
    625   if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
    626     return;
    627 
    628   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
    629       web_ui()->GetController());
    630   print_preview_ui->OnPrintPreviewRequest(request_id);
    631   // Add an additional key in order to identify |print_preview_ui| later on
    632   // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
    633   // thread.
    634   settings->SetInteger(printing::kPreviewUIID,
    635                        print_preview_ui->GetIDForPrintPreviewUI());
    636 
    637   // Increment request count.
    638   ++regenerate_preview_request_count_;
    639 
    640   WebContents* initiator = GetInitiator();
    641   if (!initiator) {
    642     ReportUserActionHistogram(INITIATOR_CLOSED);
    643     print_preview_ui->OnClosePrintPreviewDialog();
    644     return;
    645   }
    646 
    647   // Retrieve the page title and url and send it to the renderer process if
    648   // headers and footers are to be displayed.
    649   bool display_header_footer = false;
    650   if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
    651                             &display_header_footer)) {
    652     NOTREACHED();
    653   }
    654   if (display_header_footer) {
    655     settings->SetString(printing::kSettingHeaderFooterTitle,
    656                         initiator->GetTitle());
    657     std::string url;
    658     content::NavigationEntry* entry =
    659         initiator->GetController().GetLastCommittedEntry();
    660     if (entry)
    661       url = entry->GetVirtualURL().spec();
    662     settings->SetString(printing::kSettingHeaderFooterURL, url);
    663   }
    664 
    665   bool generate_draft_data = false;
    666   bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
    667                                       &generate_draft_data);
    668   DCHECK(success);
    669 
    670   if (!generate_draft_data) {
    671     double draft_page_count_double = -1;
    672     success = args->GetDouble(1, &draft_page_count_double);
    673     DCHECK(success);
    674     int draft_page_count = static_cast<int>(draft_page_count_double);
    675 
    676     bool preview_modifiable = false;
    677     success = args->GetBoolean(2, &preview_modifiable);
    678     DCHECK(success);
    679 
    680     if (draft_page_count != -1 && preview_modifiable &&
    681         print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
    682       settings->SetBoolean(printing::kSettingGenerateDraftData, true);
    683     }
    684   }
    685 
    686   VLOG(1) << "Print preview request start";
    687   RenderViewHost* rvh = initiator->GetRenderViewHost();
    688   rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
    689 }
    690 
    691 void PrintPreviewHandler::HandlePrint(const ListValue* args) {
    692   ReportStats();
    693 
    694   // Record the number of times the user requests to regenerate preview data
    695   // before printing.
    696   UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
    697                        regenerate_preview_request_count_);
    698 
    699   WebContents* initiator = GetInitiator();
    700   if (initiator) {
    701     RenderViewHost* rvh = initiator->GetRenderViewHost();
    702     rvh->Send(new PrintMsg_ResetScriptedPrintCount(rvh->GetRoutingID()));
    703   }
    704 
    705   scoped_ptr<DictionaryValue> settings(GetSettingsDictionary(args));
    706   if (!settings.get())
    707     return;
    708 
    709   // Never try to add headers/footers here. It's already in the generated PDF.
    710   settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
    711 
    712   bool print_to_pdf = false;
    713   bool is_cloud_printer = false;
    714   bool print_with_privet = false;
    715 
    716   bool open_pdf_in_preview = false;
    717 #if defined(OS_MACOSX)
    718   open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
    719 #endif
    720 
    721   if (!open_pdf_in_preview) {
    722     settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
    723     settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
    724     is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
    725   }
    726 
    727   int page_count = 0;
    728   settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
    729 
    730   if (print_to_pdf) {
    731     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
    732     ReportUserActionHistogram(PRINT_TO_PDF);
    733     PrintToPdf();
    734     return;
    735   }
    736 
    737 #if defined(ENABLE_MDNS)
    738   if (print_with_privet && PrivetPrintingEnabled()) {
    739     std::string printer_name;
    740     std::string print_ticket;
    741     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
    742     ReportUserActionHistogram(PRINT_WITH_PRIVET);
    743 
    744     int width = 0;
    745     int height = 0;
    746     if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
    747         !settings->GetString(printing::kSettingTicket, &print_ticket) ||
    748         !settings->GetInteger(printing::kSettingPageWidth, &width) ||
    749         !settings->GetInteger(printing::kSettingPageHeight, &height) ||
    750         width <= 0 || height <=0) {
    751       NOTREACHED();
    752       base::FundamentalValue http_code_value(-1);
    753       web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
    754       return;
    755     }
    756 
    757     PrintToPrivetPrinter(printer_name, print_ticket, gfx::Size(width, height));
    758     return;
    759   }
    760 #endif
    761 
    762   scoped_refptr<base::RefCountedBytes> data;
    763   base::string16 title;
    764   if (!GetPreviewDataAndTitle(&data, &title)) {
    765     // Nothing to print, no preview available.
    766     return;
    767   }
    768 
    769   if (is_cloud_printer) {
    770     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
    771                          page_count);
    772     ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
    773     SendCloudPrintJob(data.get());
    774   } else {
    775     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
    776     ReportUserActionHistogram(PRINT_TO_PRINTER);
    777     ReportPrintSettingsStats(*settings);
    778 
    779     // This tries to activate the initiator as well, so do not clear the
    780     // association with the initiator yet.
    781     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
    782         web_ui()->GetController());
    783     print_preview_ui->OnHidePreviewDialog();
    784 
    785     // Do this so the initiator can open a new print preview dialog, while the
    786     // current print preview dialog is still handling its print job.
    787     ClearInitiatorDetails();
    788 
    789     // The PDF being printed contains only the pages that the user selected,
    790     // so ignore the page range and print all pages.
    791     settings->Remove(printing::kSettingPageRange, NULL);
    792     // Reset selection only flag for the same reason.
    793     settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
    794 
    795 #if defined(USE_CUPS)
    796     if (!open_pdf_in_preview)  // We can get here even for cloud printers.
    797       ConvertColorSettingToCUPSColorModel(settings.get());
    798 #endif
    799 
    800     // Set ID to know whether printing is for preview.
    801     settings->SetInteger(printing::kPreviewUIID,
    802                          print_preview_ui->GetIDForPrintPreviewUI());
    803     RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
    804     rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
    805                                                 *settings));
    806 
    807     // For all other cases above, the preview dialog will stay open until the
    808     // printing has finished. Then the dialog closes and PrintPreviewDone() gets
    809     // called. In the case below, since the preview dialog will be hidden and
    810     // not closed, we need to make this call.
    811     if (initiator) {
    812       printing::PrintViewManager* print_view_manager =
    813           printing::PrintViewManager::FromWebContents(initiator);
    814       print_view_manager->PrintPreviewDone();
    815     }
    816   }
    817 }
    818 
    819 void PrintPreviewHandler::PrintToPdf() {
    820   if (!print_to_pdf_path_.empty()) {
    821     // User has already selected a path, no need to show the dialog again.
    822     PostPrintToPdfTask();
    823   } else if (!select_file_dialog_.get() ||
    824              !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
    825                  preview_web_contents()->GetView()->GetNativeView()))) {
    826     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
    827         web_ui()->GetController());
    828     // Pre-populating select file dialog with print job title.
    829     base::string16 print_job_title_utf16 = print_preview_ui->initiator_title();
    830 
    831 #if defined(OS_WIN)
    832     base::FilePath::StringType print_job_title(print_job_title_utf16);
    833 #elif defined(OS_POSIX)
    834     base::FilePath::StringType print_job_title =
    835         UTF16ToUTF8(print_job_title_utf16);
    836 #endif
    837 
    838     file_util::ReplaceIllegalCharactersInPath(&print_job_title, '_');
    839     base::FilePath default_filename(print_job_title);
    840     default_filename =
    841         default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
    842 
    843     SelectFile(default_filename);
    844   }
    845 }
    846 
    847 void PrintPreviewHandler::HandleHidePreview(const ListValue* /*args*/) {
    848   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
    849       web_ui()->GetController());
    850   print_preview_ui->OnHidePreviewDialog();
    851 }
    852 
    853 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
    854     const ListValue* /*args*/) {
    855   WebContents* initiator = GetInitiator();
    856   if (initiator)
    857     ClearInitiatorDetails();
    858   gfx::NativeWindow parent = initiator ?
    859       initiator->GetView()->GetTopLevelNativeWindow() :
    860       NULL;
    861   chrome::ShowPrintErrorDialog(parent);
    862 }
    863 
    864 void PrintPreviewHandler::HandleSaveAppState(const ListValue* args) {
    865   std::string data_to_save;
    866   printing::StickySettings* sticky_settings = GetStickySettings();
    867   if (args->GetString(0, &data_to_save) && !data_to_save.empty())
    868     sticky_settings->StoreAppState(data_to_save);
    869   sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
    870       preview_web_contents()->GetBrowserContext())->GetPrefs());
    871 }
    872 
    873 void PrintPreviewHandler::HandleGetPrinterCapabilities(const ListValue* args) {
    874   std::string printer_name;
    875   bool ret = args->GetString(0, &printer_name);
    876   if (!ret || printer_name.empty())
    877     return;
    878 
    879   GetPrinterCapabilitiesSuccessCallback success_cb =
    880       base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
    881                  weak_factory_.GetWeakPtr());
    882   GetPrinterCapabilitiesFailureCallback failure_cb =
    883       base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
    884                  weak_factory_.GetWeakPtr());
    885   BrowserThread::PostTask(
    886       BrowserThread::FILE, FROM_HERE,
    887       base::Bind(&GetPrinterCapabilitiesOnFileThread,
    888                  print_backend_, printer_name, success_cb, failure_cb));
    889 }
    890 
    891 void PrintPreviewHandler::OnSigninComplete() {
    892   PrintPreviewUI* print_preview_ui =
    893       static_cast<PrintPreviewUI*>(web_ui()->GetController());
    894   if (print_preview_ui)
    895     print_preview_ui->OnReloadPrintersList();
    896 }
    897 
    898 void PrintPreviewHandler::HandleSignin(const ListValue* /*args*/) {
    899   gfx::NativeWindow modal_parent = platform_util::GetTopLevel(
    900       preview_web_contents()->GetView()->GetNativeView());
    901   print_dialog_cloud::CreateCloudPrintSigninDialog(
    902       preview_web_contents()->GetBrowserContext(),
    903       modal_parent,
    904       base::Bind(&PrintPreviewHandler::OnSigninComplete,
    905                  weak_factory_.GetWeakPtr()));
    906 }
    907 
    908 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
    909   std::string type;
    910   if (!args->GetString(0, &type))
    911     return;
    912   if (!token_service_)
    913     token_service_.reset(new AccessTokenService(this));
    914   token_service_->RequestToken(type);
    915 }
    916 
    917 void PrintPreviewHandler::PrintWithCloudPrintDialog() {
    918   // Record the number of times the user asks to print via cloud print
    919   // instead of the print preview dialog.
    920   ReportStats();
    921 
    922   scoped_refptr<base::RefCountedBytes> data;
    923   base::string16 title;
    924   if (!GetPreviewDataAndTitle(&data, &title)) {
    925     // Nothing to print, no preview available.
    926     return;
    927   }
    928 
    929   gfx::NativeWindow modal_parent = platform_util::GetTopLevel(
    930       preview_web_contents()->GetView()->GetNativeView());
    931   print_dialog_cloud::CreatePrintDialogForBytes(
    932       preview_web_contents()->GetBrowserContext(),
    933       modal_parent,
    934       data.get(),
    935       title,
    936       base::string16(),
    937       std::string("application/pdf"));
    938 
    939   // Once the cloud print dialog comes up we're no longer in a background
    940   // printing situation.  Close the print preview.
    941   // TODO(abodenha (at) chromium.org) The flow should be changed as described in
    942   // http://code.google.com/p/chromium/issues/detail?id=44093
    943   ClosePreviewDialog();
    944 }
    945 
    946 void PrintPreviewHandler::HandleManageCloudPrint(const ListValue* /*args*/) {
    947   ++manage_cloud_printers_dialog_request_count_;
    948   Profile* profile = Profile::FromBrowserContext(
    949       preview_web_contents()->GetBrowserContext());
    950   preview_web_contents()->OpenURL(
    951       content::OpenURLParams(
    952           CloudPrintURL(profile).GetCloudPrintServiceManageURL(),
    953           content::Referrer(),
    954           NEW_FOREGROUND_TAB,
    955           content::PAGE_TRANSITION_LINK,
    956           false));
    957 }
    958 
    959 void PrintPreviewHandler::HandleShowSystemDialog(const ListValue* /*args*/) {
    960   ReportStats();
    961   ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
    962 
    963   WebContents* initiator = GetInitiator();
    964   if (!initiator)
    965     return;
    966 
    967   printing::PrintViewManager* print_view_manager =
    968       printing::PrintViewManager::FromWebContents(initiator);
    969   print_view_manager->set_observer(this);
    970   print_view_manager->PrintForSystemDialogNow();
    971 
    972   // Cancel the pending preview request if exists.
    973   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
    974       web_ui()->GetController());
    975   print_preview_ui->OnCancelPendingPreviewRequest();
    976 }
    977 
    978 void PrintPreviewHandler::HandleManagePrinters(const ListValue* /*args*/) {
    979   ++manage_printers_dialog_request_count_;
    980   printing::PrinterManagerDialog::ShowPrinterManagerDialog();
    981 }
    982 
    983 void PrintPreviewHandler::HandlePrintWithCloudPrintDialog(
    984     const base::ListValue* args) {
    985   int page_count = 0;
    986   if (!args || !args->GetInteger(0, &page_count))
    987     return;
    988   UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
    989                        page_count);
    990 
    991   PrintWithCloudPrintDialog();
    992 }
    993 
    994 void PrintPreviewHandler::HandleClosePreviewDialog(const ListValue* /*args*/) {
    995   ReportStats();
    996   ReportUserActionHistogram(CANCEL);
    997 
    998   // Record the number of times the user requests to regenerate preview data
    999   // before cancelling.
   1000   UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
   1001                        regenerate_preview_request_count_);
   1002 }
   1003 
   1004 void PrintPreviewHandler::ReportStats() {
   1005   UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
   1006                        manage_printers_dialog_request_count_);
   1007   UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
   1008                        manage_cloud_printers_dialog_request_count_);
   1009 }
   1010 
   1011 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
   1012     base::DictionaryValue* settings) {
   1013 
   1014   // Getting the measurement system based on the locale.
   1015   UErrorCode errorCode = U_ZERO_ERROR;
   1016   const char* locale = g_browser_process->GetApplicationLocale().c_str();
   1017   UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
   1018   if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
   1019     system = UMS_SI;
   1020 
   1021   // Getting the number formatting based on the locale and writing to
   1022   // dictionary.
   1023   settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
   1024   settings->SetInteger(kMeasurementSystem, system);
   1025 }
   1026 
   1027 void PrintPreviewHandler::HandleGetInitialSettings(const ListValue* /*args*/) {
   1028   // Send before SendInitialSettings to allow cloud printer auto select.
   1029   SendCloudPrintEnabled();
   1030   BrowserThread::PostTaskAndReplyWithResult(
   1031       BrowserThread::FILE, FROM_HERE,
   1032       base::Bind(&GetDefaultPrinterOnFileThread, print_backend_),
   1033       base::Bind(&PrintPreviewHandler::SendInitialSettings,
   1034                  weak_factory_.GetWeakPtr()));
   1035 }
   1036 
   1037 void PrintPreviewHandler::HandleReportUiEvent(const ListValue* args) {
   1038   int event_group, event_number;
   1039   if (!args->GetInteger(0, &event_group) || !args->GetInteger(1, &event_number))
   1040     return;
   1041 
   1042   enum UiBucketGroups ui_bucket_group =
   1043       static_cast<enum UiBucketGroups>(event_group);
   1044   if (ui_bucket_group >= UI_BUCKET_GROUP_BOUNDARY)
   1045     return;
   1046 
   1047   switch (ui_bucket_group) {
   1048     case DESTINATION_SEARCH: {
   1049       enum PrintDestinationBuckets event =
   1050           static_cast<enum PrintDestinationBuckets>(event_number);
   1051       if (event >= PRINT_DESTINATION_BUCKET_BOUNDARY)
   1052         return;
   1053       ReportPrintDestinationHistogram(event);
   1054       break;
   1055     }
   1056     case GCP_PROMO: {
   1057       enum GcpPromoBuckets event =
   1058           static_cast<enum GcpPromoBuckets>(event_number);
   1059       if (event >= GCP_PROMO_BUCKET_BOUNDARY)
   1060         return;
   1061       ReportGcpPromoHistogram(event);
   1062       break;
   1063     }
   1064     default:
   1065       break;
   1066   }
   1067 }
   1068 
   1069 void PrintPreviewHandler::HandleForceOpenNewTab(const ListValue* args) {
   1070   std::string url;
   1071   if (!args->GetString(0, &url))
   1072     return;
   1073   Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
   1074   if (!browser)
   1075     return;
   1076   chrome::AddSelectedTabWithURL(browser,
   1077                                 GURL(url),
   1078                                 content::PAGE_TRANSITION_LINK);
   1079 }
   1080 
   1081 void PrintPreviewHandler::SendInitialSettings(
   1082     const std::string& default_printer) {
   1083   PrintPreviewUI* print_preview_ui =
   1084       static_cast<PrintPreviewUI*>(web_ui()->GetController());
   1085 
   1086   base::DictionaryValue initial_settings;
   1087   initial_settings.SetString(kInitiatorTitle,
   1088                              print_preview_ui->initiator_title());
   1089   initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
   1090                               print_preview_ui->source_is_modifiable());
   1091   initial_settings.SetString(printing::kSettingPrinterName, default_printer);
   1092   initial_settings.SetBoolean(kDocumentHasSelection,
   1093                               print_preview_ui->source_has_selection());
   1094   initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
   1095                               print_preview_ui->print_selection_only());
   1096   printing::StickySettings* sticky_settings = GetStickySettings();
   1097   sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
   1098       preview_web_contents()->GetBrowserContext())->GetPrefs());
   1099   if (sticky_settings->printer_app_state())
   1100     initial_settings.SetString(kAppState,
   1101                                *sticky_settings->printer_app_state());
   1102 
   1103   CommandLine* cmdline = CommandLine::ForCurrentProcess();
   1104   initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
   1105                               cmdline->HasSwitch(switches::kKioskModePrinting));
   1106 #if defined(OS_WIN)
   1107   // In Win8 metro, the system print dialog can only open on the desktop.  Doing
   1108   // so will cause the browser to appear hung, so we don't show the link in
   1109   // metro.
   1110   bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
   1111   initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
   1112 #endif
   1113 
   1114   if (print_preview_ui->source_is_modifiable())
   1115     GetNumberFormatAndMeasurementSystem(&initial_settings);
   1116   web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
   1117 }
   1118 
   1119 void PrintPreviewHandler::ClosePreviewDialog() {
   1120   PrintPreviewUI* print_preview_ui =
   1121       static_cast<PrintPreviewUI*>(web_ui()->GetController());
   1122   print_preview_ui->OnClosePrintPreviewDialog();
   1123 }
   1124 
   1125 void PrintPreviewHandler::SendAccessToken(const std::string& type,
   1126                                           const std::string& access_token) {
   1127   VLOG(1) << "Get getAccessToken finished";
   1128   web_ui()->CallJavascriptFunction("onDidGetAccessToken", StringValue(type),
   1129                                    StringValue(access_token));
   1130 }
   1131 
   1132 void PrintPreviewHandler::SendPrinterCapabilities(
   1133     const DictionaryValue* settings_info) {
   1134   VLOG(1) << "Get printer capabilities finished";
   1135 
   1136 #if defined(USE_CUPS)
   1137   SaveCUPSColorSetting(settings_info);
   1138 #endif
   1139 
   1140   web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
   1141                                    *settings_info);
   1142 }
   1143 
   1144 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
   1145     const std::string& printer_name) {
   1146   VLOG(1) << "Get printer capabilities failed";
   1147   base::StringValue printer_name_value(printer_name);
   1148   web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
   1149                                    printer_name_value);
   1150 }
   1151 
   1152 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
   1153   if (!has_logged_printers_count_) {
   1154     UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
   1155     has_logged_printers_count_ = true;
   1156   }
   1157 
   1158   web_ui()->CallJavascriptFunction("setPrinters", *printers);
   1159 }
   1160 
   1161 void PrintPreviewHandler::SendCloudPrintEnabled() {
   1162   Profile* profile = Profile::FromBrowserContext(
   1163       preview_web_contents()->GetBrowserContext());
   1164   PrefService* prefs = profile->GetPrefs();
   1165   if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
   1166     GURL gcp_url(CloudPrintURL(profile).GetCloudPrintServiceURL());
   1167     base::StringValue gcp_url_value(gcp_url.spec());
   1168     web_ui()->CallJavascriptFunction("setUseCloudPrint", gcp_url_value);
   1169   }
   1170 }
   1171 
   1172 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
   1173   // BASE64 encode the job data.
   1174   std::string raw_data(reinterpret_cast<const char*>(data->front()),
   1175                        data->size());
   1176   std::string base64_data;
   1177   base::Base64Encode(raw_data, &base64_data);
   1178   StringValue data_value(base64_data);
   1179 
   1180   web_ui()->CallJavascriptFunction("printToCloud", data_value);
   1181 }
   1182 
   1183 WebContents* PrintPreviewHandler::GetInitiator() const {
   1184   printing::PrintPreviewDialogController* dialog_controller =
   1185       printing::PrintPreviewDialogController::GetInstance();
   1186   if (!dialog_controller)
   1187     return NULL;
   1188   return dialog_controller->GetInitiator(preview_web_contents());
   1189 }
   1190 
   1191 void PrintPreviewHandler::OnPrintDialogShown() {
   1192   ClosePreviewDialog();
   1193 }
   1194 
   1195 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename) {
   1196   ui::SelectFileDialog::FileTypeInfo file_type_info;
   1197   file_type_info.extensions.resize(1);
   1198   file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
   1199 
   1200   // Initializing |save_path_| if it is not already initialized.
   1201   printing::StickySettings* sticky_settings = GetStickySettings();
   1202   if (!sticky_settings->save_path()) {
   1203     // Allowing IO operation temporarily. It is ok to do so here because
   1204     // the select file dialog performs IO anyway in order to display the
   1205     // folders and also it is modal.
   1206     base::ThreadRestrictions::ScopedAllowIO allow_io;
   1207     base::FilePath file_path;
   1208     PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
   1209     sticky_settings->StoreSavePath(file_path);
   1210     sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
   1211         preview_web_contents()->GetBrowserContext())->GetPrefs());
   1212   }
   1213 
   1214   select_file_dialog_ = ui::SelectFileDialog::Create(
   1215       this, new ChromeSelectFilePolicy(preview_web_contents())),
   1216   select_file_dialog_->SelectFile(
   1217       ui::SelectFileDialog::SELECT_SAVEAS_FILE,
   1218       base::string16(),
   1219       sticky_settings->save_path()->Append(default_filename),
   1220       &file_type_info,
   1221       0,
   1222       base::FilePath::StringType(),
   1223       platform_util::GetTopLevel(
   1224           preview_web_contents()->GetView()->GetNativeView()),
   1225       NULL);
   1226 }
   1227 
   1228 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
   1229   WebContents* initiator = GetInitiator();
   1230   if (!initiator)
   1231     return;
   1232 
   1233   printing::PrintViewManager* print_view_manager =
   1234       printing::PrintViewManager::FromWebContents(initiator);
   1235   print_view_manager->set_observer(NULL);
   1236 }
   1237 
   1238 void PrintPreviewHandler::OnPrintPreviewFailed() {
   1239   if (reported_failed_preview_)
   1240     return;
   1241   reported_failed_preview_ = true;
   1242   ReportUserActionHistogram(PREVIEW_FAILED);
   1243 }
   1244 
   1245 void PrintPreviewHandler::ShowSystemDialog() {
   1246   HandleShowSystemDialog(NULL);
   1247 }
   1248 
   1249 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
   1250                                        int index, void* params) {
   1251   // Updating |save_path_| to the newly selected folder.
   1252   printing::StickySettings* sticky_settings = GetStickySettings();
   1253   sticky_settings->StoreSavePath(path.DirName());
   1254   sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
   1255       preview_web_contents()->GetBrowserContext())->GetPrefs());
   1256   web_ui()->CallJavascriptFunction("fileSelectionCompleted");
   1257   print_to_pdf_path_ = path;
   1258   PostPrintToPdfTask();
   1259 }
   1260 
   1261 void PrintPreviewHandler::PostPrintToPdfTask() {
   1262   scoped_refptr<base::RefCountedBytes> data;
   1263   base::string16 title;
   1264   if (!GetPreviewDataAndTitle(&data, &title)) {
   1265     NOTREACHED() << "Preview data was checked before file dialog.";
   1266     return;
   1267   }
   1268   scoped_ptr<printing::PreviewMetafile> metafile(new printing::PreviewMetafile);
   1269   metafile->InitFromData(static_cast<const void*>(data->front()), data->size());
   1270   BrowserThread::PostTask(
   1271       BrowserThread::FILE, FROM_HERE,
   1272       base::Bind(&PrintToPdfCallback, metafile.release(), print_to_pdf_path_));
   1273   print_to_pdf_path_ = base::FilePath();
   1274   ClosePreviewDialog();
   1275 }
   1276 
   1277 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
   1278   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
   1279       web_ui()->GetController());
   1280   print_preview_ui->OnFileSelectionCancelled();
   1281 }
   1282 
   1283 void PrintPreviewHandler::ClearInitiatorDetails() {
   1284   WebContents* initiator = GetInitiator();
   1285   if (!initiator)
   1286     return;
   1287 
   1288   // We no longer require the initiator details. Remove those details associated
   1289   // with the preview dialog to allow the initiator to create another preview
   1290   // dialog.
   1291   printing::PrintPreviewDialogController* dialog_controller =
   1292       printing::PrintPreviewDialogController::GetInstance();
   1293   if (dialog_controller)
   1294     dialog_controller->EraseInitiatorInfo(preview_web_contents());
   1295 }
   1296 
   1297 bool PrintPreviewHandler::GetPreviewDataAndTitle(
   1298     scoped_refptr<base::RefCountedBytes>* data,
   1299     base::string16* title) const {
   1300   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
   1301       web_ui()->GetController());
   1302   scoped_refptr<base::RefCountedBytes> tmp_data;
   1303   print_preview_ui->GetPrintPreviewDataForIndex(
   1304       printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
   1305 
   1306   if (!tmp_data.get()) {
   1307     // Nothing to print, no preview available.
   1308     return false;
   1309   }
   1310   DCHECK(tmp_data->size() && tmp_data->front());
   1311 
   1312   *data = tmp_data;
   1313   *title = print_preview_ui->initiator_title();
   1314   return true;
   1315 }
   1316 
   1317 #if defined(USE_CUPS)
   1318 void PrintPreviewHandler::SaveCUPSColorSetting(
   1319     const base::DictionaryValue* settings) {
   1320   cups_printer_color_models_.reset(new CUPSPrinterColorModels);
   1321   settings->GetString(kPrinterId, &cups_printer_color_models_->printer_name);
   1322   settings->GetInteger(
   1323       kCUPSsColorModel,
   1324       reinterpret_cast<int*>(&cups_printer_color_models_->color_model));
   1325   settings->GetInteger(
   1326       kCUPSsBWModel,
   1327       reinterpret_cast<int*>(&cups_printer_color_models_->bw_model));
   1328 }
   1329 
   1330 void PrintPreviewHandler::ConvertColorSettingToCUPSColorModel(
   1331     base::DictionaryValue* settings) const {
   1332   if (!cups_printer_color_models_)
   1333     return;
   1334 
   1335   // Sanity check the printer name.
   1336   std::string printer_name;
   1337   if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
   1338       printer_name != cups_printer_color_models_->printer_name) {
   1339     NOTREACHED();
   1340     return;
   1341   }
   1342 
   1343   int color;
   1344   if (!settings->GetInteger(printing::kSettingColor, &color)) {
   1345     NOTREACHED();
   1346     return;
   1347   }
   1348 
   1349   if (color == printing::GRAY) {
   1350     if (cups_printer_color_models_->bw_model != printing::UNKNOWN_COLOR_MODEL) {
   1351       settings->SetInteger(printing::kSettingColor,
   1352                            cups_printer_color_models_->bw_model);
   1353     }
   1354     return;
   1355   }
   1356 
   1357   printing::ColorModel color_model = cups_printer_color_models_->color_model;
   1358   if (color_model != printing::UNKNOWN_COLOR_MODEL)
   1359     settings->SetInteger(printing::kSettingColor, color_model);
   1360 }
   1361 
   1362 #endif
   1363 
   1364 
   1365 #if defined(ENABLE_MDNS)
   1366 void PrintPreviewHandler::LocalPrinterChanged(
   1367     bool added,
   1368     const std::string& name,
   1369     bool has_local_printing,
   1370     const local_discovery::DeviceDescription& description) {
   1371   CommandLine* command_line = CommandLine::ForCurrentProcess();
   1372   if (has_local_printing ||
   1373       (command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos) &&
   1374        description.id.empty())) {
   1375     base::DictionaryValue info;
   1376     FillPrinterDescription(name, description, has_local_printing, &info);
   1377     web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
   1378   }
   1379 }
   1380 
   1381 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
   1382 }
   1383 
   1384 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
   1385 }
   1386 
   1387 void PrintPreviewHandler::StopPrivetPrinterSearch() {
   1388   printer_lister_->Stop();
   1389   web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
   1390 }
   1391 
   1392 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
   1393     scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
   1394   if (!PrivetUpdateClient(http_client.Pass()))
   1395     return;
   1396 
   1397   privet_capabilities_operation_ =
   1398       privet_http_client_->CreateCapabilitiesOperation(
   1399           this);
   1400   privet_capabilities_operation_->Start();
   1401 }
   1402 
   1403 bool PrintPreviewHandler::PrivetUpdateClient(
   1404     scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
   1405   if (!http_client) {
   1406     SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
   1407     privet_http_resolution_.reset();
   1408     return false;
   1409   }
   1410 
   1411   privet_local_print_operation_.reset();
   1412   privet_capabilities_operation_.reset();
   1413   privet_http_client_ = http_client.Pass();
   1414 
   1415   privet_http_resolution_.reset();
   1416 
   1417   return true;
   1418 }
   1419 
   1420 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
   1421     std::string print_ticket,
   1422     gfx::Size page_size,
   1423     scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
   1424   if (!PrivetUpdateClient(http_client.Pass()))
   1425     return;
   1426 
   1427   StartPrivetLocalPrint(print_ticket, page_size);
   1428 }
   1429 
   1430 void PrintPreviewHandler::StartPrivetLocalPrint(
   1431     const std::string& print_ticket,
   1432     const gfx::Size& page_size) {
   1433   privet_local_print_operation_ =
   1434       privet_http_client_->CreateLocalPrintOperation(this);
   1435 
   1436   privet_local_print_operation_->SetTicket(print_ticket);
   1437 
   1438   scoped_refptr<base::RefCountedBytes> data;
   1439   base::string16 title;
   1440 
   1441   if (!GetPreviewDataAndTitle(&data, &title)) {
   1442     base::FundamentalValue http_code_value(-1);
   1443     web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
   1444     return;
   1445   }
   1446 
   1447   privet_local_print_operation_->SetJobname(
   1448       base::UTF16ToUTF8(title));
   1449 
   1450   const int dpi = printing::kDefaultPdfDpi;
   1451   double scale = dpi;
   1452   scale /= printing::kPointsPerInch;
   1453   // Make vertical rectangle to optimize streaming to printer. Fix orientation
   1454   // by autorotate.
   1455   gfx::Rect area(std::min(page_size.width(), page_size.height()) * scale,
   1456                  std::max(page_size.width(), page_size.height()) * scale);
   1457   privet_local_print_operation_->SetConversionSettings(
   1458       printing::PdfRenderSettings(area, dpi, true));
   1459 
   1460   privet_local_print_operation_->SetData(data);
   1461 
   1462   Profile* profile = Profile::FromWebUI(web_ui());
   1463   SigninManagerBase* signin_manager =
   1464       SigninManagerFactory::GetForProfileIfExists(profile);
   1465 
   1466   if (signin_manager) {
   1467     privet_local_print_operation_->SetUsername(
   1468         signin_manager->GetAuthenticatedUsername());
   1469   }
   1470 
   1471   privet_local_print_operation_->Start();
   1472 }
   1473 
   1474 
   1475 void PrintPreviewHandler::OnPrivetCapabilities(
   1476     local_discovery::PrivetCapabilitiesOperation* capabilities_operation,
   1477     int http_error,
   1478     const base::DictionaryValue* capabilities) {
   1479   std::string name = capabilities_operation->GetHTTPClient()->GetName();
   1480 
   1481   if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError)) {
   1482     SendPrivetCapabilitiesError(name);
   1483     return;
   1484   }
   1485 
   1486   base::DictionaryValue printer_info;
   1487   const local_discovery::DeviceDescription* description =
   1488       printer_lister_->GetDeviceDescription(name);
   1489 
   1490   if (!description) {
   1491     SendPrivetCapabilitiesError(name);
   1492     return;
   1493   }
   1494 
   1495   FillPrinterDescription(name, *description, true, &printer_info);
   1496 
   1497   web_ui()->CallJavascriptFunction(
   1498       "onPrivetCapabilitiesSet",
   1499       printer_info,
   1500       *capabilities);
   1501 
   1502   privet_capabilities_operation_.reset();
   1503 }
   1504 
   1505 void PrintPreviewHandler::SendPrivetCapabilitiesError(
   1506     const std::string& device_name) {
   1507   base::StringValue name_value(device_name);
   1508   web_ui()->CallJavascriptFunction(
   1509       "failedToGetPrivetPrinterCapabilities",
   1510       name_value);
   1511 }
   1512 
   1513 void PrintPreviewHandler::PrintToPrivetPrinter(
   1514     const std::string& device_name,
   1515     const std::string& ticket,
   1516     const gfx::Size& page_size) {
   1517   CreatePrivetHTTP(
   1518       device_name,
   1519       base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
   1520                  base::Unretained(this), ticket, page_size));
   1521 }
   1522 
   1523 bool PrintPreviewHandler::CreatePrivetHTTP(
   1524     const std::string& name,
   1525     const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
   1526     callback) {
   1527   const local_discovery::DeviceDescription* device_description =
   1528       printer_lister_->GetDeviceDescription(name);
   1529 
   1530   if (!device_description) {
   1531     SendPrivetCapabilitiesError(name);
   1532     return false;
   1533   }
   1534 
   1535   privet_http_factory_ =
   1536       local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
   1537       service_discovery_client_,
   1538       Profile::FromWebUI(web_ui())->GetRequestContext());
   1539   privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
   1540       name,
   1541       device_description->address,
   1542       callback);
   1543   privet_http_resolution_->Start();
   1544 
   1545   return true;
   1546 }
   1547 
   1548 void PrintPreviewHandler::OnPrivetPrintingDone(
   1549     const local_discovery::PrivetLocalPrintOperation* print_operation) {
   1550   ClosePreviewDialog();
   1551 }
   1552 
   1553 void PrintPreviewHandler::OnPrivetPrintingError(
   1554     const local_discovery::PrivetLocalPrintOperation* print_operation,
   1555     int http_code) {
   1556   base::FundamentalValue http_code_value(http_code);
   1557   web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
   1558 }
   1559 
   1560 void PrintPreviewHandler::FillPrinterDescription(
   1561     const std::string& name,
   1562     const local_discovery::DeviceDescription& description,
   1563     bool has_local_printing,
   1564     base::DictionaryValue* printer_value) {
   1565   printer_value->SetString("serviceName", name);
   1566   printer_value->SetString("name", description.name);
   1567   printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
   1568   printer_value->SetBoolean("isUnregistered", description.id.empty());
   1569   printer_value->SetString("cloudID", description.id);
   1570 }
   1571 
   1572 #endif
   1573