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