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.
5 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
11 #include "base/base64.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/command_line.h"
15 #include "base/i18n/file_util_icu.h"
16 #include "base/i18n/number_formatting.h"
17 #include "base/json/json_reader.h"
18 #include "base/lazy_instance.h"
19 #include "base/memory/linked_ptr.h"
20 #include "base/memory/ref_counted_memory.h"
21 #include "base/metrics/histogram.h"
22 #include "base/path_service.h"
23 #include "base/prefs/pref_service.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/threading/thread.h"
26 #include "base/threading/thread_restrictions.h"
27 #include "base/values.h"
28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/platform_util.h"
30 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
31 #include "chrome/browser/printing/print_dialog_cloud.h"
32 #include "chrome/browser/printing/print_error_dialog.h"
33 #include "chrome/browser/printing/print_job_manager.h"
34 #include "chrome/browser/printing/print_preview_dialog_controller.h"
35 #include "chrome/browser/printing/print_view_manager.h"
36 #include "chrome/browser/printing/printer_manager_dialog.h"
37 #include "chrome/browser/profiles/profile.h"
38 #include "chrome/browser/signin/profile_oauth2_token_service.h"
39 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
40 #include "chrome/browser/signin/signin_manager.h"
41 #include "chrome/browser/signin/signin_manager_base.h"
42 #include "chrome/browser/signin/signin_manager_factory.h"
43 #include "chrome/browser/ui/browser_finder.h"
44 #include "chrome/browser/ui/browser_tabstrip.h"
45 #include "chrome/browser/ui/chrome_select_file_policy.h"
46 #include "chrome/browser/ui/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_constants.h"
52 #include "chrome/common/crash_keys.h"
53 #include "chrome/common/pref_names.h"
54 #include "chrome/common/print_messages.h"
55 #include "content/public/browser/browser_context.h"
56 #include "content/public/browser/browser_thread.h"
57 #include "content/public/browser/navigation_controller.h"
58 #include "content/public/browser/navigation_entry.h"
59 #include "content/public/browser/render_view_host.h"
60 #include "content/public/browser/web_contents.h"
61 #include "content/public/browser/web_contents_view.h"
62 #include "content/public/browser/web_ui.h"
63 #include "google_apis/gaia/oauth2_token_service.h"
64 #include "printing/backend/print_backend.h"
65 #include "printing/metafile.h"
66 #include "printing/metafile_impl.h"
67 #include "printing/pdf_render_settings.h"
68 #include "printing/print_settings.h"
69 #include "printing/units.h"
70 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
72 #if defined(OS_CHROMEOS)
73 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
74 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
77 #if defined(ENABLE_MDNS)
78 #include "chrome/browser/local_discovery/privet_constants.h"
81 using content::BrowserThread;
82 using content::RenderViewHost;
83 using content::WebContents;
87 enum UserActionBuckets {
91 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
94 INITIATOR_CRASHED, // UNUSED
96 PRINT_WITH_CLOUD_PRINT,
98 USERACTION_BUCKET_BOUNDARY
101 enum PrintSettingsBuckets {
113 PRINT_SETTINGS_BUCKET_BOUNDARY
116 enum UiBucketGroups {
119 UI_BUCKET_GROUP_BOUNDARY
122 enum PrintDestinationBuckets {
124 DESTINATION_CLOSED_CHANGED,
125 DESTINATION_CLOSED_UNCHANGED,
128 PRIVET_DUPLICATE_SELECTED,
129 CLOUD_DUPLICATE_SELECTED,
130 PRINT_DESTINATION_BUCKET_BOUNDARY
133 enum GcpPromoBuckets {
137 GCP_PROMO_BUCKET_BOUNDARY
140 void ReportUserActionHistogram(enum UserActionBuckets event) {
141 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
142 USERACTION_BUCKET_BOUNDARY);
145 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
146 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
147 PRINT_SETTINGS_BUCKET_BOUNDARY);
150 void ReportPrintDestinationHistogram(enum PrintDestinationBuckets event) {
151 UMA_HISTOGRAM_ENUMERATION("PrintPreview.DestinationAction", event,
152 PRINT_DESTINATION_BUCKET_BOUNDARY);
155 void ReportGcpPromoHistogram(enum GcpPromoBuckets event) {
156 UMA_HISTOGRAM_ENUMERATION("PrintPreview.GcpPromo", event,
157 GCP_PROMO_BUCKET_BOUNDARY);
160 // Name of a dictionary field holding cloud print related data;
161 const char kAppState[] = "appState";
162 // Name of a dictionary field holding the initiator title.
163 const char kInitiatorTitle[] = "initiatorTitle";
164 // Name of a dictionary field holding the measurement system according to the
166 const char kMeasurementSystem[] = "measurementSystem";
167 // Name of a dictionary field holding the number format according to the locale.
168 const char kNumberFormat[] = "numberFormat";
169 // Name of a dictionary field specifying whether to print automatically in
170 // kiosk mode. See http://crbug.com/31395.
171 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
173 const char kHidePrintWithSystemDialogLink[] = "hidePrintWithSystemDialogLink";
175 // Name of a dictionary field holding the state of selection for document.
176 const char kDocumentHasSelection[] = "documentHasSelection";
178 // Additional printer capability setting keys.
179 const char kPrinterId[] = "printerId";
180 const char kDisableColorOption[] = "disableColorOption";
181 const char kSetDuplexAsDefault[] = "setDuplexAsDefault";
182 const char kPrinterDefaultDuplexValue[] = "printerDefaultDuplexValue";
183 #if defined(USE_CUPS)
184 const char kCUPSsColorModel[] = "cupsColorModel";
185 const char kCUPSsBWModel[] = "cupsBWModel";
188 // Get the print job settings dictionary from |args|. The caller takes
189 // ownership of the returned DictionaryValue. Returns NULL on failure.
190 base::DictionaryValue* GetSettingsDictionary(const base::ListValue* args) {
191 std::string json_str;
192 if (!args->GetString(0, &json_str)) {
193 NOTREACHED() << "Could not read JSON argument";
196 if (json_str.empty()) {
197 NOTREACHED() << "Empty print job settings";
200 scoped_ptr<base::DictionaryValue> settings(
201 static_cast<base::DictionaryValue*>(
202 base::JSONReader::Read(json_str)));
203 if (!settings.get() || !settings->IsType(base::Value::TYPE_DICTIONARY)) {
204 NOTREACHED() << "Print job settings must be a dictionary.";
208 if (settings->empty()) {
209 NOTREACHED() << "Print job settings dictionary is empty";
213 return settings.release();
216 // Track the popularity of print settings and report the stats.
217 void ReportPrintSettingsStats(const base::DictionaryValue& settings) {
218 ReportPrintSettingHistogram(TOTAL);
220 bool landscape = false;
221 if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
222 ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
224 bool collate = false;
225 if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
226 ReportPrintSettingHistogram(COLLATE);
229 if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
230 ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
233 if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
234 ReportPrintSettingHistogram(
235 printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
238 bool headers = false;
239 if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) &&
241 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
244 bool css_background = false;
245 if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
246 &css_background) && css_background) {
247 ReportPrintSettingHistogram(CSS_BACKGROUND);
250 bool selection_only = false;
251 if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
252 &selection_only) && selection_only) {
253 ReportPrintSettingHistogram(SELECTION_ONLY);
257 // Callback that stores a PDF file on disk.
258 void PrintToPdfCallback(printing::Metafile* metafile,
259 const base::FilePath& path) {
260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
261 metafile->SaveTo(path);
262 // |metafile| must be deleted on the UI thread.
263 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, metafile);
266 std::string GetDefaultPrinterOnFileThread(
267 scoped_refptr<printing::PrintBackend> print_backend) {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
270 std::string default_printer = print_backend->GetDefaultPrinterName();
271 VLOG(1) << "Default Printer: " << default_printer;
272 return default_printer;
275 void EnumeratePrintersOnFileThread(
276 scoped_refptr<printing::PrintBackend> print_backend,
277 base::ListValue* printers) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
280 VLOG(1) << "Enumerate printers start";
281 printing::PrinterList printer_list;
282 print_backend->EnumeratePrinters(&printer_list);
284 for (printing::PrinterList::iterator it = printer_list.begin();
285 it != printer_list.end(); ++it) {
286 base::DictionaryValue* printer_info = new base::DictionaryValue;
287 std::string printer_name;
288 #if defined(OS_MACOSX)
289 // On Mac, |it->printer_description| specifies the printer name and
290 // |it->printer_name| specifies the device name / printer queue name.
291 printer_name = it->printer_description;
293 printer_name = it->printer_name;
295 printer_info->SetString(printing::kSettingPrinterName, printer_name);
296 printer_info->SetString(printing::kSettingDeviceName, it->printer_name);
297 VLOG(1) << "Found printer " << printer_name
298 << " with device name " << it->printer_name;
299 printers->Append(printer_info);
301 VLOG(1) << "Enumerate printers finished, found " << printers->GetSize()
305 typedef base::Callback<void(const base::DictionaryValue*)>
306 GetPrinterCapabilitiesSuccessCallback;
307 typedef base::Callback<void(const std::string&)>
308 GetPrinterCapabilitiesFailureCallback;
310 void GetPrinterCapabilitiesOnFileThread(
311 scoped_refptr<printing::PrintBackend> print_backend,
312 const std::string& printer_name,
313 const GetPrinterCapabilitiesSuccessCallback& success_cb,
314 const GetPrinterCapabilitiesFailureCallback& failure_cb) {
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
316 DCHECK(!printer_name.empty());
318 VLOG(1) << "Get printer capabilities start for " << printer_name;
319 crash_keys::ScopedPrinterInfo crash_key(
320 print_backend->GetPrinterDriverInfo(printer_name));
322 if (!print_backend->IsValidPrinter(printer_name)) {
323 // TODO(gene): Notify explicitly if printer is not valid, instead of
324 // failed to get capabilities.
325 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
326 base::Bind(failure_cb, printer_name));
330 printing::PrinterSemanticCapsAndDefaults info;
331 if (!print_backend->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
332 LOG(WARNING) << "Failed to get capabilities for " << printer_name;
333 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
334 base::Bind(failure_cb, printer_name));
338 scoped_ptr<base::DictionaryValue> settings_info(new base::DictionaryValue);
339 settings_info->SetString(kPrinterId, printer_name);
340 settings_info->SetBoolean(kDisableColorOption, !info.color_changeable);
341 settings_info->SetBoolean(printing::kSettingSetColorAsDefault,
343 #if defined(USE_CUPS)
344 settings_info->SetInteger(kCUPSsColorModel, info.color_model);
345 settings_info->SetInteger(kCUPSsBWModel, info.bw_model);
348 // TODO(gene): Make new capabilities format for Print Preview
349 // that will suit semantic capabiltities better.
350 // Refactor pld API code below
351 bool default_duplex = info.duplex_capable ?
352 (info.duplex_default != printing::SIMPLEX) : false;
353 int duplex_value = info.duplex_capable ?
354 printing::LONG_EDGE : printing::UNKNOWN_DUPLEX_MODE;
355 settings_info->SetBoolean(kSetDuplexAsDefault, default_duplex);
356 settings_info->SetInteger(kPrinterDefaultDuplexValue, duplex_value);
358 BrowserThread::PostTask(
359 BrowserThread::UI, FROM_HERE,
360 base::Bind(success_cb, base::Owned(settings_info.release())));
363 base::LazyInstance<printing::StickySettings> g_sticky_settings =
364 LAZY_INSTANCE_INITIALIZER;
366 printing::StickySettings* GetStickySettings() {
367 return g_sticky_settings.Pointer();
372 #if defined(USE_CUPS)
373 struct PrintPreviewHandler::CUPSPrinterColorModels {
374 std::string printer_name;
375 printing::ColorModel color_model;
376 printing::ColorModel bw_model;
380 class PrintPreviewHandler::AccessTokenService
381 : public OAuth2TokenService::Consumer {
383 explicit AccessTokenService(PrintPreviewHandler* handler)
384 : OAuth2TokenService::Consumer("print_preview"),
386 weak_factory_(this) {
389 void RequestToken(const std::string& type) {
390 if (requests_.find(type) != requests_.end())
391 return; // Already in progress.
393 OAuth2TokenService* service = NULL;
394 std::string account_id;
395 if (type == "profile") {
396 Profile* profile = Profile::FromWebUI(handler_->web_ui());
398 ProfileOAuth2TokenService* token_service =
399 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
400 SigninManagerBase* signin_manager =
401 SigninManagerFactory::GetInstance()->GetForProfile(profile);
402 account_id = signin_manager->GetAuthenticatedAccountId();
403 service = token_service;
405 } else if (type == "device") {
406 #if defined(OS_CHROMEOS)
407 chromeos::DeviceOAuth2TokenServiceFactory::Get(
409 &AccessTokenService::DidGetTokenService,
410 weak_factory_.GetWeakPtr(),
416 ContinueRequestToken(type, service, account_id);
419 #if defined(OS_CHROMEOS)
420 // Continuation of RequestToken().
421 void DidGetTokenService(const std::string& type,
422 chromeos::DeviceOAuth2TokenService* token_service) {
423 std::string account_id;
425 account_id = token_service->GetRobotAccountId();
426 ContinueRequestToken(type,
432 // Continuation of RequestToken().
433 void ContinueRequestToken(const std::string& type,
434 OAuth2TokenService* service,
435 const std::string& account_id) {
437 OAuth2TokenService::ScopeSet oauth_scopes;
438 oauth_scopes.insert(cloud_print::kCloudPrintAuth);
439 scoped_ptr<OAuth2TokenService::Request> request(
440 service->StartRequest(account_id, oauth_scopes, this));
441 requests_[type].reset(request.release());
443 handler_->SendAccessToken(type, std::string()); // Unknown type.
447 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
448 const std::string& access_token,
449 const base::Time& expiration_time) OVERRIDE {
450 OnServiceResponce(request, access_token);
453 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
454 const GoogleServiceAuthError& error) OVERRIDE {
455 OnServiceResponce(request, std::string());
459 void OnServiceResponce(const OAuth2TokenService::Request* request,
460 const std::string& access_token) {
461 for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
462 if (i->second == request) {
463 handler_->SendAccessToken(i->first, access_token);
471 typedef std::map<std::string,
472 linked_ptr<OAuth2TokenService::Request> > Requests;
474 PrintPreviewHandler* handler_;
475 base::WeakPtrFactory<AccessTokenService> weak_factory_;
477 DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
480 PrintPreviewHandler::PrintPreviewHandler()
481 : print_backend_(printing::PrintBackend::CreateInstance(NULL)),
482 regenerate_preview_request_count_(0),
483 manage_printers_dialog_request_count_(0),
484 manage_cloud_printers_dialog_request_count_(0),
485 reported_failed_preview_(false),
486 has_logged_printers_count_(false),
487 weak_factory_(this) {
488 ReportUserActionHistogram(PREVIEW_STARTED);
491 PrintPreviewHandler::~PrintPreviewHandler() {
492 if (select_file_dialog_.get())
493 select_file_dialog_->ListenerDestroyed();
496 void PrintPreviewHandler::RegisterMessages() {
497 web_ui()->RegisterMessageCallback("getPrinters",
498 base::Bind(&PrintPreviewHandler::HandleGetPrinters,
499 base::Unretained(this)));
500 web_ui()->RegisterMessageCallback("getPreview",
501 base::Bind(&PrintPreviewHandler::HandleGetPreview,
502 base::Unretained(this)));
503 web_ui()->RegisterMessageCallback("print",
504 base::Bind(&PrintPreviewHandler::HandlePrint,
505 base::Unretained(this)));
506 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
507 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
508 base::Unretained(this)));
509 web_ui()->RegisterMessageCallback("showSystemDialog",
510 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
511 base::Unretained(this)));
512 web_ui()->RegisterMessageCallback("signIn",
513 base::Bind(&PrintPreviewHandler::HandleSignin,
514 base::Unretained(this)));
515 web_ui()->RegisterMessageCallback("getAccessToken",
516 base::Bind(&PrintPreviewHandler::HandleGetAccessToken,
517 base::Unretained(this)));
518 web_ui()->RegisterMessageCallback("manageCloudPrinters",
519 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
520 base::Unretained(this)));
521 web_ui()->RegisterMessageCallback("manageLocalPrinters",
522 base::Bind(&PrintPreviewHandler::HandleManagePrinters,
523 base::Unretained(this)));
524 web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
525 base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog,
526 base::Unretained(this)));
527 web_ui()->RegisterMessageCallback("hidePreview",
528 base::Bind(&PrintPreviewHandler::HandleHidePreview,
529 base::Unretained(this)));
530 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
531 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
532 base::Unretained(this)));
533 web_ui()->RegisterMessageCallback("saveAppState",
534 base::Bind(&PrintPreviewHandler::HandleSaveAppState,
535 base::Unretained(this)));
536 web_ui()->RegisterMessageCallback("getInitialSettings",
537 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
538 base::Unretained(this)));
539 web_ui()->RegisterMessageCallback("reportUiEvent",
540 base::Bind(&PrintPreviewHandler::HandleReportUiEvent,
541 base::Unretained(this)));
542 web_ui()->RegisterMessageCallback("printWithCloudPrintDialog",
543 base::Bind(&PrintPreviewHandler::HandlePrintWithCloudPrintDialog,
544 base::Unretained(this)));
545 web_ui()->RegisterMessageCallback("forceOpenNewTab",
546 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
547 base::Unretained(this)));
548 web_ui()->RegisterMessageCallback("getPrivetPrinters",
549 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
550 base::Unretained(this)));
551 web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
552 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
553 base::Unretained(this)));
554 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
555 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
556 base::Unretained(this)));
559 bool PrintPreviewHandler::PrivetPrintingEnabled() {
560 #if defined(ENABLE_MDNS)
561 CommandLine* command_line = CommandLine::ForCurrentProcess();
562 return !command_line->HasSwitch(switches::kDisableDeviceDiscovery) &&
563 !command_line->HasSwitch(switches::kDisablePrivetLocalPrinting);
569 WebContents* PrintPreviewHandler::preview_web_contents() const {
570 return web_ui()->GetWebContents();
573 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
574 base::ListValue* results = new base::ListValue;
575 BrowserThread::PostTaskAndReply(
576 BrowserThread::FILE, FROM_HERE,
577 base::Bind(&EnumeratePrintersOnFileThread, print_backend_,
578 base::Unretained(results)),
579 base::Bind(&PrintPreviewHandler::SetupPrinterList,
580 weak_factory_.GetWeakPtr(),
581 base::Owned(results)));
584 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
585 #if defined(ENABLE_MDNS)
586 if (PrivetPrintingEnabled()) {
587 Profile* profile = Profile::FromWebUI(web_ui());
588 service_discovery_client_ =
589 local_discovery::ServiceDiscoverySharedClient::GetInstance();
590 printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
591 service_discovery_client_.get(),
592 profile->GetRequestContext(),
594 printer_lister_->Start();
598 if (!PrivetPrintingEnabled()) {
599 web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
603 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
604 const base::ListValue* args) {
605 #if defined(ENABLE_MDNS)
606 if (PrivetPrintingEnabled()) {
607 printer_lister_->Stop();
612 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
613 const base::ListValue* args) {
614 #if defined(ENABLE_MDNS)
616 bool success = args->GetString(0, &name);
621 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
622 base::Unretained(this)));
626 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
627 DCHECK_EQ(3U, args->GetSize());
628 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
632 if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
635 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
636 web_ui()->GetController());
637 print_preview_ui->OnPrintPreviewRequest(request_id);
638 // Add an additional key in order to identify |print_preview_ui| later on
639 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
641 settings->SetInteger(printing::kPreviewUIID,
642 print_preview_ui->GetIDForPrintPreviewUI());
644 // Increment request count.
645 ++regenerate_preview_request_count_;
647 WebContents* initiator = GetInitiator();
649 ReportUserActionHistogram(INITIATOR_CLOSED);
650 print_preview_ui->OnClosePrintPreviewDialog();
654 // Retrieve the page title and url and send it to the renderer process if
655 // headers and footers are to be displayed.
656 bool display_header_footer = false;
657 if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
658 &display_header_footer)) {
661 if (display_header_footer) {
662 settings->SetString(printing::kSettingHeaderFooterTitle,
663 initiator->GetTitle());
665 content::NavigationEntry* entry =
666 initiator->GetController().GetLastCommittedEntry();
668 url = entry->GetVirtualURL().spec();
669 settings->SetString(printing::kSettingHeaderFooterURL, url);
672 bool generate_draft_data = false;
673 bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
674 &generate_draft_data);
677 if (!generate_draft_data) {
678 double draft_page_count_double = -1;
679 success = args->GetDouble(1, &draft_page_count_double);
681 int draft_page_count = static_cast<int>(draft_page_count_double);
683 bool preview_modifiable = false;
684 success = args->GetBoolean(2, &preview_modifiable);
687 if (draft_page_count != -1 && preview_modifiable &&
688 print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
689 settings->SetBoolean(printing::kSettingGenerateDraftData, true);
693 VLOG(1) << "Print preview request start";
694 RenderViewHost* rvh = initiator->GetRenderViewHost();
695 rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
698 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
701 // Record the number of times the user requests to regenerate preview data
703 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
704 regenerate_preview_request_count_);
706 WebContents* initiator = GetInitiator();
708 RenderViewHost* rvh = initiator->GetRenderViewHost();
709 rvh->Send(new PrintMsg_ResetScriptedPrintCount(rvh->GetRoutingID()));
712 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
716 // Never try to add headers/footers here. It's already in the generated PDF.
717 settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
719 bool print_to_pdf = false;
720 bool is_cloud_printer = false;
721 bool print_with_privet = false;
723 bool open_pdf_in_preview = false;
724 #if defined(OS_MACOSX)
725 open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
728 if (!open_pdf_in_preview) {
729 settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
730 settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
731 is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
735 settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
738 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
739 ReportUserActionHistogram(PRINT_TO_PDF);
744 #if defined(ENABLE_MDNS)
745 if (print_with_privet && PrivetPrintingEnabled()) {
746 std::string printer_name;
747 std::string print_ticket;
748 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
749 ReportUserActionHistogram(PRINT_WITH_PRIVET);
753 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
754 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
755 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
756 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
757 width <= 0 || height <=0) {
759 base::FundamentalValue http_code_value(-1);
760 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
764 PrintToPrivetPrinter(printer_name, print_ticket, gfx::Size(width, height));
769 scoped_refptr<base::RefCountedBytes> data;
770 base::string16 title;
771 if (!GetPreviewDataAndTitle(&data, &title)) {
772 // Nothing to print, no preview available.
776 if (is_cloud_printer) {
777 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
779 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
780 SendCloudPrintJob(data.get());
782 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
783 ReportUserActionHistogram(PRINT_TO_PRINTER);
784 ReportPrintSettingsStats(*settings);
786 // This tries to activate the initiator as well, so do not clear the
787 // association with the initiator yet.
788 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
789 web_ui()->GetController());
790 print_preview_ui->OnHidePreviewDialog();
792 // Do this so the initiator can open a new print preview dialog, while the
793 // current print preview dialog is still handling its print job.
794 ClearInitiatorDetails();
796 // The PDF being printed contains only the pages that the user selected,
797 // so ignore the page range and print all pages.
798 settings->Remove(printing::kSettingPageRange, NULL);
799 // Reset selection only flag for the same reason.
800 settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
802 #if defined(USE_CUPS)
803 if (!open_pdf_in_preview) // We can get here even for cloud printers.
804 ConvertColorSettingToCUPSColorModel(settings.get());
807 // Set ID to know whether printing is for preview.
808 settings->SetInteger(printing::kPreviewUIID,
809 print_preview_ui->GetIDForPrintPreviewUI());
810 RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
811 rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
814 // For all other cases above, the preview dialog will stay open until the
815 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
816 // called. In the case below, since the preview dialog will be hidden and
817 // not closed, we need to make this call.
819 printing::PrintViewManager* print_view_manager =
820 printing::PrintViewManager::FromWebContents(initiator);
821 print_view_manager->PrintPreviewDone();
826 void PrintPreviewHandler::PrintToPdf() {
827 if (!print_to_pdf_path_.empty()) {
828 // User has already selected a path, no need to show the dialog again.
829 PostPrintToPdfTask();
830 } else if (!select_file_dialog_.get() ||
831 !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
832 preview_web_contents()->GetView()->GetNativeView()))) {
833 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
834 web_ui()->GetController());
835 // Pre-populating select file dialog with print job title.
836 base::string16 print_job_title_utf16 = print_preview_ui->initiator_title();
839 base::FilePath::StringType print_job_title(print_job_title_utf16);
840 #elif defined(OS_POSIX)
841 base::FilePath::StringType print_job_title =
842 base::UTF16ToUTF8(print_job_title_utf16);
845 file_util::ReplaceIllegalCharactersInPath(&print_job_title, '_');
846 base::FilePath default_filename(print_job_title);
848 default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
850 SelectFile(default_filename);
854 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
855 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
856 web_ui()->GetController());
857 print_preview_ui->OnHidePreviewDialog();
860 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
861 const base::ListValue* /*args*/) {
862 WebContents* initiator = GetInitiator();
864 ClearInitiatorDetails();
865 gfx::NativeWindow parent = initiator ?
866 initiator->GetView()->GetTopLevelNativeWindow() :
868 chrome::ShowPrintErrorDialog(parent);
871 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
872 std::string data_to_save;
873 printing::StickySettings* sticky_settings = GetStickySettings();
874 if (args->GetString(0, &data_to_save) && !data_to_save.empty())
875 sticky_settings->StoreAppState(data_to_save);
876 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
877 preview_web_contents()->GetBrowserContext())->GetPrefs());
880 void PrintPreviewHandler::HandleGetPrinterCapabilities(
881 const base::ListValue* args) {
882 std::string printer_name;
883 bool ret = args->GetString(0, &printer_name);
884 if (!ret || printer_name.empty())
887 GetPrinterCapabilitiesSuccessCallback success_cb =
888 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
889 weak_factory_.GetWeakPtr());
890 GetPrinterCapabilitiesFailureCallback failure_cb =
891 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
892 weak_factory_.GetWeakPtr());
893 BrowserThread::PostTask(
894 BrowserThread::FILE, FROM_HERE,
895 base::Bind(&GetPrinterCapabilitiesOnFileThread,
896 print_backend_, printer_name, success_cb, failure_cb));
899 void PrintPreviewHandler::OnSigninComplete() {
900 PrintPreviewUI* print_preview_ui =
901 static_cast<PrintPreviewUI*>(web_ui()->GetController());
902 if (print_preview_ui)
903 print_preview_ui->OnReloadPrintersList();
906 void PrintPreviewHandler::HandleSignin(const base::ListValue* /*args*/) {
907 Profile* profile = Profile::FromBrowserContext(
908 preview_web_contents()->GetBrowserContext());
909 chrome::ScopedTabbedBrowserDisplayer displayer(
910 profile, chrome::GetActiveDesktop());
911 print_dialog_cloud::CreateCloudPrintSigninTab(
913 base::Bind(&PrintPreviewHandler::OnSigninComplete,
914 weak_factory_.GetWeakPtr()));
917 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
919 if (!args->GetString(0, &type))
922 token_service_.reset(new AccessTokenService(this));
923 token_service_->RequestToken(type);
926 void PrintPreviewHandler::PrintWithCloudPrintDialog() {
927 // Record the number of times the user asks to print via cloud print
928 // instead of the print preview dialog.
931 scoped_refptr<base::RefCountedBytes> data;
932 base::string16 title;
933 if (!GetPreviewDataAndTitle(&data, &title)) {
934 // Nothing to print, no preview available.
938 gfx::NativeWindow modal_parent = platform_util::GetTopLevel(
939 preview_web_contents()->GetView()->GetNativeView());
940 print_dialog_cloud::CreatePrintDialogForBytes(
941 preview_web_contents()->GetBrowserContext(),
946 std::string("application/pdf"));
948 // Once the cloud print dialog comes up we're no longer in a background
949 // printing situation. Close the print preview.
950 // TODO(abodenha@chromium.org) The flow should be changed as described in
951 // http://code.google.com/p/chromium/issues/detail?id=44093
952 ClosePreviewDialog();
955 void PrintPreviewHandler::HandleManageCloudPrint(
956 const base::ListValue* /*args*/) {
957 ++manage_cloud_printers_dialog_request_count_;
958 Profile* profile = Profile::FromBrowserContext(
959 preview_web_contents()->GetBrowserContext());
960 preview_web_contents()->OpenURL(
961 content::OpenURLParams(
962 CloudPrintURL(profile).GetCloudPrintServiceManageURL(),
965 content::PAGE_TRANSITION_LINK,
969 void PrintPreviewHandler::HandleShowSystemDialog(
970 const base::ListValue* /*args*/) {
972 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
974 WebContents* initiator = GetInitiator();
978 printing::PrintViewManager* print_view_manager =
979 printing::PrintViewManager::FromWebContents(initiator);
980 print_view_manager->set_observer(this);
981 print_view_manager->PrintForSystemDialogNow();
983 // Cancel the pending preview request if exists.
984 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
985 web_ui()->GetController());
986 print_preview_ui->OnCancelPendingPreviewRequest();
989 void PrintPreviewHandler::HandleManagePrinters(
990 const base::ListValue* /*args*/) {
991 ++manage_printers_dialog_request_count_;
992 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
995 void PrintPreviewHandler::HandlePrintWithCloudPrintDialog(
996 const base::ListValue* args) {
998 if (!args || !args->GetInteger(0, &page_count))
1000 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
1003 PrintWithCloudPrintDialog();
1006 void PrintPreviewHandler::HandleClosePreviewDialog(
1007 const base::ListValue* /*args*/) {
1009 ReportUserActionHistogram(CANCEL);
1011 // Record the number of times the user requests to regenerate preview data
1012 // before cancelling.
1013 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1014 regenerate_preview_request_count_);
1017 void PrintPreviewHandler::ReportStats() {
1018 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1019 manage_printers_dialog_request_count_);
1020 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1021 manage_cloud_printers_dialog_request_count_);
1024 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1025 base::DictionaryValue* settings) {
1027 // Getting the measurement system based on the locale.
1028 UErrorCode errorCode = U_ZERO_ERROR;
1029 const char* locale = g_browser_process->GetApplicationLocale().c_str();
1030 UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1031 if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1034 // Getting the number formatting based on the locale and writing to
1036 settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1037 settings->SetInteger(kMeasurementSystem, system);
1040 void PrintPreviewHandler::HandleGetInitialSettings(
1041 const base::ListValue* /*args*/) {
1042 // Send before SendInitialSettings to allow cloud printer auto select.
1043 SendCloudPrintEnabled();
1044 BrowserThread::PostTaskAndReplyWithResult(
1045 BrowserThread::FILE, FROM_HERE,
1046 base::Bind(&GetDefaultPrinterOnFileThread, print_backend_),
1047 base::Bind(&PrintPreviewHandler::SendInitialSettings,
1048 weak_factory_.GetWeakPtr()));
1051 void PrintPreviewHandler::HandleReportUiEvent(const base::ListValue* args) {
1052 int event_group, event_number;
1053 if (!args->GetInteger(0, &event_group) || !args->GetInteger(1, &event_number))
1056 enum UiBucketGroups ui_bucket_group =
1057 static_cast<enum UiBucketGroups>(event_group);
1058 if (ui_bucket_group >= UI_BUCKET_GROUP_BOUNDARY)
1061 switch (ui_bucket_group) {
1062 case DESTINATION_SEARCH: {
1063 enum PrintDestinationBuckets event =
1064 static_cast<enum PrintDestinationBuckets>(event_number);
1065 if (event >= PRINT_DESTINATION_BUCKET_BOUNDARY)
1067 ReportPrintDestinationHistogram(event);
1071 enum GcpPromoBuckets event =
1072 static_cast<enum GcpPromoBuckets>(event_number);
1073 if (event >= GCP_PROMO_BUCKET_BOUNDARY)
1075 ReportGcpPromoHistogram(event);
1083 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1085 if (!args->GetString(0, &url))
1087 Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1090 chrome::AddSelectedTabWithURL(browser,
1092 content::PAGE_TRANSITION_LINK);
1095 void PrintPreviewHandler::SendInitialSettings(
1096 const std::string& default_printer) {
1097 PrintPreviewUI* print_preview_ui =
1098 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1100 base::DictionaryValue initial_settings;
1101 initial_settings.SetString(kInitiatorTitle,
1102 print_preview_ui->initiator_title());
1103 initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1104 print_preview_ui->source_is_modifiable());
1105 initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1106 initial_settings.SetBoolean(kDocumentHasSelection,
1107 print_preview_ui->source_has_selection());
1108 initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1109 print_preview_ui->print_selection_only());
1110 printing::StickySettings* sticky_settings = GetStickySettings();
1111 sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1112 preview_web_contents()->GetBrowserContext())->GetPrefs());
1113 if (sticky_settings->printer_app_state())
1114 initial_settings.SetString(kAppState,
1115 *sticky_settings->printer_app_state());
1117 CommandLine* cmdline = CommandLine::ForCurrentProcess();
1118 initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1119 cmdline->HasSwitch(switches::kKioskModePrinting));
1121 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1122 // so will cause the browser to appear hung, so we don't show the link in
1124 bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1125 initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1128 if (print_preview_ui->source_is_modifiable())
1129 GetNumberFormatAndMeasurementSystem(&initial_settings);
1130 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1133 void PrintPreviewHandler::ClosePreviewDialog() {
1134 PrintPreviewUI* print_preview_ui =
1135 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1136 print_preview_ui->OnClosePrintPreviewDialog();
1139 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1140 const std::string& access_token) {
1141 VLOG(1) << "Get getAccessToken finished";
1142 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1143 base::StringValue(type),
1144 base::StringValue(access_token));
1147 void PrintPreviewHandler::SendPrinterCapabilities(
1148 const base::DictionaryValue* settings_info) {
1149 VLOG(1) << "Get printer capabilities finished";
1151 #if defined(USE_CUPS)
1152 SaveCUPSColorSetting(settings_info);
1155 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1159 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1160 const std::string& printer_name) {
1161 VLOG(1) << "Get printer capabilities failed";
1162 base::StringValue printer_name_value(printer_name);
1163 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1164 printer_name_value);
1167 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1168 if (!has_logged_printers_count_) {
1169 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1170 has_logged_printers_count_ = true;
1173 web_ui()->CallJavascriptFunction("setPrinters", *printers);
1176 void PrintPreviewHandler::SendCloudPrintEnabled() {
1177 Profile* profile = Profile::FromBrowserContext(
1178 preview_web_contents()->GetBrowserContext());
1179 PrefService* prefs = profile->GetPrefs();
1180 if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1181 GURL gcp_url(CloudPrintURL(profile).GetCloudPrintServiceURL());
1182 base::StringValue gcp_url_value(gcp_url.spec());
1183 web_ui()->CallJavascriptFunction("setUseCloudPrint", gcp_url_value);
1187 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1188 // BASE64 encode the job data.
1189 std::string raw_data(reinterpret_cast<const char*>(data->front()),
1191 std::string base64_data;
1192 base::Base64Encode(raw_data, &base64_data);
1193 base::StringValue data_value(base64_data);
1195 web_ui()->CallJavascriptFunction("printToCloud", data_value);
1198 WebContents* PrintPreviewHandler::GetInitiator() const {
1199 printing::PrintPreviewDialogController* dialog_controller =
1200 printing::PrintPreviewDialogController::GetInstance();
1201 if (!dialog_controller)
1203 return dialog_controller->GetInitiator(preview_web_contents());
1206 void PrintPreviewHandler::OnPrintDialogShown() {
1207 ClosePreviewDialog();
1210 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename) {
1211 ui::SelectFileDialog::FileTypeInfo file_type_info;
1212 file_type_info.extensions.resize(1);
1213 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1215 // Initializing |save_path_| if it is not already initialized.
1216 printing::StickySettings* sticky_settings = GetStickySettings();
1217 if (!sticky_settings->save_path()) {
1218 // Allowing IO operation temporarily. It is ok to do so here because
1219 // the select file dialog performs IO anyway in order to display the
1220 // folders and also it is modal.
1221 base::ThreadRestrictions::ScopedAllowIO allow_io;
1222 base::FilePath file_path;
1223 PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1224 sticky_settings->StoreSavePath(file_path);
1225 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1226 preview_web_contents()->GetBrowserContext())->GetPrefs());
1229 select_file_dialog_ = ui::SelectFileDialog::Create(
1230 this, new ChromeSelectFilePolicy(preview_web_contents())),
1231 select_file_dialog_->SelectFile(
1232 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1234 sticky_settings->save_path()->Append(default_filename),
1237 base::FilePath::StringType(),
1238 platform_util::GetTopLevel(
1239 preview_web_contents()->GetView()->GetNativeView()),
1243 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1244 WebContents* initiator = GetInitiator();
1248 printing::PrintViewManager* print_view_manager =
1249 printing::PrintViewManager::FromWebContents(initiator);
1250 print_view_manager->set_observer(NULL);
1253 void PrintPreviewHandler::OnPrintPreviewFailed() {
1254 if (reported_failed_preview_)
1256 reported_failed_preview_ = true;
1257 ReportUserActionHistogram(PREVIEW_FAILED);
1260 void PrintPreviewHandler::ShowSystemDialog() {
1261 HandleShowSystemDialog(NULL);
1264 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1265 int index, void* params) {
1266 // Updating |save_path_| to the newly selected folder.
1267 printing::StickySettings* sticky_settings = GetStickySettings();
1268 sticky_settings->StoreSavePath(path.DirName());
1269 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1270 preview_web_contents()->GetBrowserContext())->GetPrefs());
1271 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1272 print_to_pdf_path_ = path;
1273 PostPrintToPdfTask();
1276 void PrintPreviewHandler::PostPrintToPdfTask() {
1277 scoped_refptr<base::RefCountedBytes> data;
1278 base::string16 title;
1279 if (!GetPreviewDataAndTitle(&data, &title)) {
1280 NOTREACHED() << "Preview data was checked before file dialog.";
1283 scoped_ptr<printing::PreviewMetafile> metafile(new printing::PreviewMetafile);
1284 metafile->InitFromData(static_cast<const void*>(data->front()), data->size());
1285 BrowserThread::PostTask(
1286 BrowserThread::FILE, FROM_HERE,
1287 base::Bind(&PrintToPdfCallback, metafile.release(), print_to_pdf_path_));
1288 print_to_pdf_path_ = base::FilePath();
1289 ClosePreviewDialog();
1292 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1293 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1294 web_ui()->GetController());
1295 print_preview_ui->OnFileSelectionCancelled();
1298 void PrintPreviewHandler::ClearInitiatorDetails() {
1299 WebContents* initiator = GetInitiator();
1303 // We no longer require the initiator details. Remove those details associated
1304 // with the preview dialog to allow the initiator to create another preview
1306 printing::PrintPreviewDialogController* dialog_controller =
1307 printing::PrintPreviewDialogController::GetInstance();
1308 if (dialog_controller)
1309 dialog_controller->EraseInitiatorInfo(preview_web_contents());
1312 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1313 scoped_refptr<base::RefCountedBytes>* data,
1314 base::string16* title) const {
1315 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1316 web_ui()->GetController());
1317 scoped_refptr<base::RefCountedBytes> tmp_data;
1318 print_preview_ui->GetPrintPreviewDataForIndex(
1319 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1321 if (!tmp_data.get()) {
1322 // Nothing to print, no preview available.
1325 DCHECK(tmp_data->size() && tmp_data->front());
1328 *title = print_preview_ui->initiator_title();
1332 #if defined(USE_CUPS)
1333 void PrintPreviewHandler::SaveCUPSColorSetting(
1334 const base::DictionaryValue* settings) {
1335 cups_printer_color_models_.reset(new CUPSPrinterColorModels);
1336 settings->GetString(kPrinterId, &cups_printer_color_models_->printer_name);
1337 settings->GetInteger(
1339 reinterpret_cast<int*>(&cups_printer_color_models_->color_model));
1340 settings->GetInteger(
1342 reinterpret_cast<int*>(&cups_printer_color_models_->bw_model));
1345 void PrintPreviewHandler::ConvertColorSettingToCUPSColorModel(
1346 base::DictionaryValue* settings) const {
1347 if (!cups_printer_color_models_)
1350 // Sanity check the printer name.
1351 std::string printer_name;
1352 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
1353 printer_name != cups_printer_color_models_->printer_name) {
1359 if (!settings->GetInteger(printing::kSettingColor, &color)) {
1364 if (color == printing::GRAY) {
1365 if (cups_printer_color_models_->bw_model != printing::UNKNOWN_COLOR_MODEL) {
1366 settings->SetInteger(printing::kSettingColor,
1367 cups_printer_color_models_->bw_model);
1372 printing::ColorModel color_model = cups_printer_color_models_->color_model;
1373 if (color_model != printing::UNKNOWN_COLOR_MODEL)
1374 settings->SetInteger(printing::kSettingColor, color_model);
1380 #if defined(ENABLE_MDNS)
1381 void PrintPreviewHandler::LocalPrinterChanged(
1383 const std::string& name,
1384 bool has_local_printing,
1385 const local_discovery::DeviceDescription& description) {
1386 base::DictionaryValue info;
1387 FillPrinterDescription(name, description, has_local_printing, &info);
1388 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1391 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1394 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1397 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1398 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1399 if (!PrivetUpdateClient(http_client.Pass()))
1402 privet_capabilities_operation_ =
1403 privet_http_client_->CreateCapabilitiesOperation(
1404 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1405 base::Unretained(this)));
1406 privet_capabilities_operation_->Start();
1409 bool PrintPreviewHandler::PrivetUpdateClient(
1410 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1412 SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1413 privet_http_resolution_.reset();
1417 privet_local_print_operation_.reset();
1418 privet_capabilities_operation_.reset();
1419 privet_http_client_ = http_client.Pass();
1421 privet_http_resolution_.reset();
1426 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1427 std::string print_ticket,
1428 gfx::Size page_size,
1429 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1430 if (!PrivetUpdateClient(http_client.Pass()))
1433 StartPrivetLocalPrint(print_ticket, page_size);
1436 void PrintPreviewHandler::StartPrivetLocalPrint(
1437 const std::string& print_ticket,
1438 const gfx::Size& page_size) {
1439 privet_local_print_operation_ =
1440 privet_http_client_->CreateLocalPrintOperation(this);
1442 privet_local_print_operation_->SetTicket(print_ticket);
1444 scoped_refptr<base::RefCountedBytes> data;
1445 base::string16 title;
1447 if (!GetPreviewDataAndTitle(&data, &title)) {
1448 base::FundamentalValue http_code_value(-1);
1449 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1453 privet_local_print_operation_->SetJobname(
1454 base::UTF16ToUTF8(title));
1456 const int dpi = printing::kDefaultPdfDpi;
1458 scale /= printing::kPointsPerInch;
1459 // Make vertical rectangle to optimize streaming to printer. Fix orientation
1461 gfx::Rect area(std::min(page_size.width(), page_size.height()) * scale,
1462 std::max(page_size.width(), page_size.height()) * scale);
1463 privet_local_print_operation_->SetConversionSettings(
1464 printing::PdfRenderSettings(area, dpi, true));
1466 privet_local_print_operation_->SetData(data);
1468 Profile* profile = Profile::FromWebUI(web_ui());
1469 SigninManagerBase* signin_manager =
1470 SigninManagerFactory::GetForProfileIfExists(profile);
1472 if (signin_manager) {
1473 privet_local_print_operation_->SetUsername(
1474 signin_manager->GetAuthenticatedUsername());
1477 privet_local_print_operation_->Start();
1481 void PrintPreviewHandler::OnPrivetCapabilities(
1482 const base::DictionaryValue* capabilities) {
1483 std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1485 if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError)) {
1486 SendPrivetCapabilitiesError(name);
1490 base::DictionaryValue printer_info;
1491 const local_discovery::DeviceDescription* description =
1492 printer_lister_->GetDeviceDescription(name);
1495 SendPrivetCapabilitiesError(name);
1499 FillPrinterDescription(name, *description, true, &printer_info);
1501 web_ui()->CallJavascriptFunction(
1502 "onPrivetCapabilitiesSet",
1506 privet_capabilities_operation_.reset();
1509 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1510 const std::string& device_name) {
1511 base::StringValue name_value(device_name);
1512 web_ui()->CallJavascriptFunction(
1513 "failedToGetPrivetPrinterCapabilities",
1517 void PrintPreviewHandler::PrintToPrivetPrinter(
1518 const std::string& device_name,
1519 const std::string& ticket,
1520 const gfx::Size& page_size) {
1523 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1524 base::Unretained(this), ticket, page_size));
1527 bool PrintPreviewHandler::CreatePrivetHTTP(
1528 const std::string& name,
1529 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1531 const local_discovery::DeviceDescription* device_description =
1532 printer_lister_->GetDeviceDescription(name);
1534 if (!device_description) {
1535 SendPrivetCapabilitiesError(name);
1539 privet_http_factory_ =
1540 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1541 service_discovery_client_,
1542 Profile::FromWebUI(web_ui())->GetRequestContext());
1543 privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
1545 device_description->address,
1547 privet_http_resolution_->Start();
1552 void PrintPreviewHandler::OnPrivetPrintingDone(
1553 const local_discovery::PrivetLocalPrintOperation* print_operation) {
1554 ClosePreviewDialog();
1557 void PrintPreviewHandler::OnPrivetPrintingError(
1558 const local_discovery::PrivetLocalPrintOperation* print_operation,
1560 base::FundamentalValue http_code_value(http_code);
1561 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1564 void PrintPreviewHandler::FillPrinterDescription(
1565 const std::string& name,
1566 const local_discovery::DeviceDescription& description,
1567 bool has_local_printing,
1568 base::DictionaryValue* printer_value) {
1569 printer_value->SetString("serviceName", name);
1570 printer_value->SetString("name", description.name);
1571 printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1572 printer_value->SetBoolean(
1574 description.id.empty());
1575 printer_value->SetString("cloudID", description.id);