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